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.data; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.StringDef; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.ServiceConnection; 29 import android.content.pm.PackageManager; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.Looper; 33 import android.os.PersistableBundle; 34 import android.os.Registrant; 35 import android.os.RegistrantList; 36 import android.os.RemoteException; 37 import android.os.SystemProperties; 38 import android.os.UserHandle; 39 import android.telephony.AccessNetworkConstants; 40 import android.telephony.AccessNetworkConstants.AccessNetworkType; 41 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; 42 import android.telephony.AccessNetworkConstants.TransportType; 43 import android.telephony.Annotation.ApnType; 44 import android.telephony.Annotation.NetCapability; 45 import android.telephony.AnomalyReporter; 46 import android.telephony.CarrierConfigManager; 47 import android.telephony.data.ApnSetting; 48 import android.telephony.data.IQualifiedNetworksService; 49 import android.telephony.data.IQualifiedNetworksServiceCallback; 50 import android.telephony.data.QualifiedNetworksService; 51 import android.telephony.data.ThrottleStatus; 52 import android.text.TextUtils; 53 import android.util.ArraySet; 54 import android.util.IndentingPrintWriter; 55 import android.util.LocalLog; 56 import android.util.SparseArray; 57 58 import com.android.internal.telephony.Phone; 59 import com.android.internal.telephony.RIL; 60 import com.android.internal.telephony.SlidingWindowEventCounter; 61 import com.android.internal.telephony.dataconnection.DataThrottler; 62 import com.android.telephony.Rlog; 63 64 import java.io.FileDescriptor; 65 import java.io.PrintWriter; 66 import java.lang.annotation.Retention; 67 import java.lang.annotation.RetentionPolicy; 68 import java.util.ArrayList; 69 import java.util.Arrays; 70 import java.util.HashSet; 71 import java.util.List; 72 import java.util.Map; 73 import java.util.Set; 74 import java.util.UUID; 75 import java.util.concurrent.ConcurrentHashMap; 76 import java.util.concurrent.Executor; 77 import java.util.stream.Collectors; 78 79 /** 80 * Access network manager manages the qualified/available networks for mobile data connection. 81 * It binds to the vendor's qualified networks service and actively monitors the qualified 82 * networks changes. 83 */ 84 public class AccessNetworksManager extends Handler { 85 private static final boolean DBG = false; 86 public static final String SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE = 87 "ro.telephony.iwlan_operation_mode"; 88 89 @Retention(RetentionPolicy.SOURCE) 90 @StringDef(prefix = {"IWLAN_OPERATION_MODE_"}, 91 value = { 92 IWLAN_OPERATION_MODE_DEFAULT, 93 IWLAN_OPERATION_MODE_LEGACY, 94 IWLAN_OPERATION_MODE_AP_ASSISTED}) 95 public @interface IwlanOperationMode {} 96 97 /** 98 * IWLAN default mode. On device that has IRadio 1.4 or above, it means 99 * {@link #IWLAN_OPERATION_MODE_AP_ASSISTED}. On device that has IRadio 1.3 or below, it means 100 * {@link #IWLAN_OPERATION_MODE_LEGACY}. 101 */ 102 public static final String IWLAN_OPERATION_MODE_DEFAULT = "default"; 103 104 /** 105 * IWLAN legacy mode. IWLAN is completely handled by the modem, and when the device is on 106 * IWLAN, modem reports IWLAN as a RAT. 107 */ 108 public static final String IWLAN_OPERATION_MODE_LEGACY = "legacy"; 109 110 /** 111 * IWLAN application processor assisted mode. IWLAN is handled by the bound IWLAN data service 112 * and network service separately. 113 */ 114 public static final String IWLAN_OPERATION_MODE_AP_ASSISTED = "AP-assisted"; 115 116 /** 117 * The counters to detect frequent QNS attempt to change preferred network transport by ApnType. 118 */ 119 private final @NonNull SparseArray<SlidingWindowEventCounter> mApnTypeToQnsChangeNetworkCounter; 120 121 private final String mLogTag; 122 private final LocalLog mLocalLog = new LocalLog(64); 123 private final UUID mAnomalyUUID = UUID.fromString("c2d1a639-00e2-4561-9619-6acf37d90590"); 124 private String mLastBoundPackageName; 125 126 public static final int[] SUPPORTED_APN_TYPES = { 127 ApnSetting.TYPE_DEFAULT, 128 ApnSetting.TYPE_MMS, 129 ApnSetting.TYPE_FOTA, 130 ApnSetting.TYPE_IMS, 131 ApnSetting.TYPE_CBS, 132 ApnSetting.TYPE_SUPL, 133 ApnSetting.TYPE_EMERGENCY, 134 ApnSetting.TYPE_XCAP, 135 ApnSetting.TYPE_DUN 136 }; 137 138 private final Phone mPhone; 139 140 private final CarrierConfigManager mCarrierConfigManager; 141 142 private @Nullable DataConfigManager mDataConfigManager; 143 144 private IQualifiedNetworksService mIQualifiedNetworksService; 145 146 private AccessNetworksManagerDeathRecipient mDeathRecipient; 147 148 private String mTargetBindingPackageName; 149 150 private QualifiedNetworksServiceConnection mServiceConnection; 151 152 // Available networks. Key is the APN type. 153 private final SparseArray<int[]> mAvailableNetworks = new SparseArray<>(); 154 155 private final @TransportType int[] mAvailableTransports; 156 157 private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList(); 158 159 private final Set<DataThrottler> mDataThrottlers = new HashSet<>(); 160 161 private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { 162 @Override 163 public void onReceive(Context context, Intent intent) { 164 final String action = intent.getAction(); 165 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) 166 && mPhone.getPhoneId() == intent.getIntExtra( 167 CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { 168 // We should wait for carrier config changed event because the target binding 169 // package name can come from the carrier config. Note that we still get this event 170 // even when SIM is absent. 171 if (DBG) log("Carrier config changed. Try to bind qualified network service."); 172 bindQualifiedNetworksService(); 173 } 174 } 175 }; 176 177 /** 178 * The current transport of the APN type. The key is the APN type, and the value is the 179 * transport. 180 */ 181 private final Map<Integer, Integer> mCurrentTransports = new ConcurrentHashMap<>(); 182 183 /** 184 * The preferred transport of the APN type. The key is the APN type, and the value is the 185 * transport. The preferred transports are updated as soon as QNS changes the preference, while 186 * the current transports are updated after handover complete. 187 */ 188 // TODO: Deprecate mPreferredTransports. Should expose mAvailableNetworks to 189 // DataNetworkController after we support multi preferred access networks (i.e. 190 // DataNetworkController might select 2nd preferred access network in some scenarios.) 191 private final Map<Integer, Integer> mPreferredTransports = new ConcurrentHashMap<>(); 192 193 /** 194 * Callbacks for passing information to interested clients. 195 */ 196 private final @NonNull Set<AccessNetworksManagerCallback> mAccessNetworksManagerCallbacks = 197 new ArraySet<>(); 198 199 /** 200 * Registers the data throttler in order to receive APN status changes. 201 * 202 * @param dataThrottler the data throttler to register 203 */ registerDataThrottler(DataThrottler dataThrottler)204 public void registerDataThrottler(DataThrottler dataThrottler) { 205 this.post(() -> { 206 QualifiedNetworksServiceConnection serviceConnection = mServiceConnection; 207 this.mDataThrottlers.add(dataThrottler); 208 if (serviceConnection != null) { 209 serviceConnection.registerDataThrottler(dataThrottler); 210 } 211 }); 212 } 213 214 /** 215 * Represents qualified network types list on a specific APN type. 216 */ 217 public static class QualifiedNetworks { 218 public final @ApnType int apnType; 219 // The qualified networks in preferred order. Each network is a AccessNetworkType. 220 public final @NonNull @RadioAccessNetworkType int[] qualifiedNetworks; QualifiedNetworks(@pnType int apnType, @NonNull int[] qualifiedNetworks)221 public QualifiedNetworks(@ApnType int apnType, @NonNull int[] qualifiedNetworks) { 222 this.apnType = apnType; 223 this.qualifiedNetworks = Arrays.stream(qualifiedNetworks) 224 .boxed() 225 .filter(DataUtils::isValidAccessNetwork) 226 .mapToInt(Integer::intValue) 227 .toArray(); 228 } 229 230 @Override toString()231 public String toString() { 232 return "[QualifiedNetworks: apnType=" 233 + ApnSetting.getApnTypeString(apnType) 234 + ", networks=" 235 + Arrays.stream(qualifiedNetworks) 236 .mapToObj(AccessNetworkType::toString) 237 .collect(Collectors.joining(",")) 238 + "]"; 239 } 240 } 241 242 private class AccessNetworksManagerDeathRecipient implements IBinder.DeathRecipient { 243 @Override binderDied()244 public void binderDied() { 245 // TODO: try to rebind the service. 246 String message = "Qualified network service " + mLastBoundPackageName + " died."; 247 // clear the anomaly report counters when QNS crash 248 mApnTypeToQnsChangeNetworkCounter.clear(); 249 loge(message); 250 AnomalyReporter.reportAnomaly(mAnomalyUUID, message, mPhone.getCarrierId()); 251 } 252 } 253 254 private final class QualifiedNetworksServiceConnection implements ServiceConnection { 255 256 /** 257 * The APN throttle status callback is attached to the service connection so that they have 258 * the same life cycle. 259 */ 260 @NonNull 261 private final ThrottleStatusChangedCallback mThrottleStatusCallback; 262 QualifiedNetworksServiceConnection()263 QualifiedNetworksServiceConnection() { 264 mThrottleStatusCallback = new ThrottleStatusChangedCallback(); 265 } 266 267 @Override onServiceConnected(ComponentName name, IBinder service)268 public void onServiceConnected(ComponentName name, IBinder service) { 269 if (DBG) log("onServiceConnected " + name); 270 mIQualifiedNetworksService = IQualifiedNetworksService.Stub.asInterface(service); 271 mDeathRecipient = new AccessNetworksManagerDeathRecipient(); 272 mLastBoundPackageName = getQualifiedNetworksServicePackageName(); 273 274 try { 275 service.linkToDeath(mDeathRecipient, 0 /* flags */); 276 mIQualifiedNetworksService.createNetworkAvailabilityProvider(mPhone.getPhoneId(), 277 new QualifiedNetworksServiceCallback()); 278 279 registerDataThrottlersFirstTime(); 280 281 } catch (RemoteException e) { 282 loge("Remote exception. " + e); 283 } 284 } 285 286 @Override onServiceDisconnected(ComponentName name)287 public void onServiceDisconnected(ComponentName name) { 288 if (DBG) log("onServiceDisconnected " + name); 289 unregisterForThrottleCallbacks(); 290 mTargetBindingPackageName = null; 291 } 292 293 /** 294 * Runs on all of the data throttlers when the service is connected 295 */ registerDataThrottlersFirstTime()296 private void registerDataThrottlersFirstTime() { 297 post(() -> { 298 for (DataThrottler dataThrottler : mDataThrottlers) { 299 dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); 300 } 301 }); 302 } 303 registerDataThrottler(DataThrottler dataThrottler)304 private void registerDataThrottler(DataThrottler dataThrottler) { 305 post(() -> { 306 dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); 307 }); 308 } 309 unregisterForThrottleCallbacks()310 private void unregisterForThrottleCallbacks() { 311 post(() -> { 312 for (DataThrottler dataThrottler : mDataThrottlers) { 313 dataThrottler.unregisterForThrottleStatusChanges(mThrottleStatusCallback); 314 } 315 }); 316 } 317 } 318 319 private class ThrottleStatusChangedCallback implements DataThrottler.Callback { 320 @Override onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses)321 public void onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses) { 322 post(() -> { 323 try { 324 List<ThrottleStatus> throttleStatusesBySlot = 325 throttleStatuses 326 .stream() 327 .filter(x -> x.getSlotIndex() == mPhone.getPhoneId()) 328 .collect(Collectors.toList()); 329 if (mIQualifiedNetworksService != null) { 330 mIQualifiedNetworksService.reportThrottleStatusChanged(mPhone.getPhoneId(), 331 throttleStatusesBySlot); 332 } 333 } catch (Exception ex) { 334 loge("onThrottleStatusChanged", ex); 335 } 336 }); 337 } 338 } 339 340 private final class QualifiedNetworksServiceCallback extends 341 IQualifiedNetworksServiceCallback.Stub { 342 @Override onQualifiedNetworkTypesChanged(int apnTypes, @NonNull int[] qualifiedNetworkTypes)343 public void onQualifiedNetworkTypesChanged(int apnTypes, 344 @NonNull int[] qualifiedNetworkTypes) { 345 if (qualifiedNetworkTypes == null) { 346 loge("onQualifiedNetworkTypesChanged: Ignored null input."); 347 return; 348 } 349 350 log("onQualifiedNetworkTypesChanged: apnTypes = [" 351 + ApnSetting.getApnTypesStringFromBitmask(apnTypes) 352 + "], networks = [" + Arrays.stream(qualifiedNetworkTypes) 353 .mapToObj(AccessNetworkType::toString).collect(Collectors.joining(",")) 354 + "]"); 355 356 if (Arrays.stream(qualifiedNetworkTypes).anyMatch(accessNetwork 357 -> !DataUtils.isValidAccessNetwork(accessNetwork))) { 358 loge("Invalid access networks " + Arrays.toString(qualifiedNetworkTypes)); 359 if (mDataConfigManager != null 360 && mDataConfigManager.isInvalidQnsParamAnomalyReportEnabled()) { 361 reportAnomaly("QNS requested invalid Network Type", 362 "3e89a3df-3524-45fa-b5f2-0fb0e4c77ec4"); 363 } 364 return; 365 } 366 367 List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>(); 368 int satisfiedApnTypes = 0; 369 for (int apnType : SUPPORTED_APN_TYPES) { 370 if ((apnTypes & apnType) == apnType) { 371 // skip the APN anomaly detection if not using the T data stack 372 if (mDataConfigManager != null) { 373 satisfiedApnTypes |= apnType; 374 } 375 376 if (mAvailableNetworks.get(apnType) != null) { 377 if (Arrays.equals(mAvailableNetworks.get(apnType), 378 qualifiedNetworkTypes)) { 379 log("Available networks for " 380 + ApnSetting.getApnTypesStringFromBitmask(apnType) 381 + " not changed."); 382 continue; 383 } 384 } 385 386 // Empty array indicates QNS did not suggest any qualified networks. In this 387 // case all network requests will be routed to cellular. 388 if (qualifiedNetworkTypes.length == 0) { 389 mAvailableNetworks.remove(apnType); 390 if (getPreferredTransport(apnType) 391 == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 392 mPreferredTransports.put(apnType, 393 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 394 mAccessNetworksManagerCallbacks.forEach(callback -> 395 callback.invokeFromExecutor(() -> 396 callback.onPreferredTransportChanged(DataUtils 397 .apnTypeToNetworkCapability(apnType)))); 398 } 399 } else { 400 mAvailableNetworks.put(apnType, qualifiedNetworkTypes); 401 qualifiedNetworksList.add(new QualifiedNetworks(apnType, 402 qualifiedNetworkTypes)); 403 404 } 405 } 406 } 407 408 // Report anomaly if any requested APN types are unsatisfied 409 if (satisfiedApnTypes != apnTypes 410 && mDataConfigManager != null 411 && mDataConfigManager.isInvalidQnsParamAnomalyReportEnabled()) { 412 int unsatisfied = satisfiedApnTypes ^ apnTypes; 413 reportAnomaly("QNS requested unsupported APN Types:" 414 + Integer.toBinaryString(unsatisfied), 415 "3e89a3df-3524-45fa-b5f2-0fb0e4c77ec5"); 416 } 417 418 if (!qualifiedNetworksList.isEmpty()) { 419 setPreferredTransports(qualifiedNetworksList); 420 mQualifiedNetworksChangedRegistrants.notifyResult(qualifiedNetworksList); 421 } 422 } 423 } 424 425 /** 426 * Access networks manager callback. This should be only used by {@link DataNetworkController}. 427 */ 428 public abstract static class AccessNetworksManagerCallback extends DataCallback { 429 /** 430 * Constructor 431 * 432 * @param executor The executor of the callback. 433 */ AccessNetworksManagerCallback(@onNull @allbackExecutor Executor executor)434 public AccessNetworksManagerCallback(@NonNull @CallbackExecutor Executor executor) { 435 super(executor); 436 } 437 438 /** 439 * Called when preferred transport changed. 440 * 441 * @param networkCapability The network capability. 442 */ onPreferredTransportChanged(@etCapability int networkCapability)443 public abstract void onPreferredTransportChanged(@NetCapability int networkCapability); 444 } 445 446 /** 447 * Constructor 448 * 449 * @param phone The phone object. 450 * @param looper Looper for the handler. 451 */ AccessNetworksManager(@onNull Phone phone, @NonNull Looper looper)452 public AccessNetworksManager(@NonNull Phone phone, @NonNull Looper looper) { 453 super(looper); 454 mPhone = phone; 455 mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( 456 Context.CARRIER_CONFIG_SERVICE); 457 mLogTag = "ANM-" + mPhone.getPhoneId(); 458 mApnTypeToQnsChangeNetworkCounter = new SparseArray<>(); 459 460 if (isInLegacyMode()) { 461 log("operates in legacy mode."); 462 // For legacy mode, WWAN is the only transport to handle all data connections, even 463 // the IWLAN ones. 464 mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN}; 465 } else { 466 log("operates in AP-assisted mode."); 467 mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 468 AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; 469 IntentFilter intentFilter = new IntentFilter(); 470 intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 471 try { 472 Context contextAsUser = phone.getContext().createPackageContextAsUser( 473 phone.getContext().getPackageName(), 0, UserHandle.ALL); 474 contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, 475 null /* broadcastPermission */, null); 476 } catch (PackageManager.NameNotFoundException e) { 477 loge("Package name not found: ", e); 478 } 479 bindQualifiedNetworksService(); 480 } 481 482 if (phone.isUsingNewDataStack()) { 483 // Using post to delay the registering because data retry manager and data config 484 // manager instances are created later than access networks manager. 485 post(() -> { 486 mPhone.getDataNetworkController().getDataRetryManager().registerCallback( 487 new DataRetryManager.DataRetryManagerCallback(this::post) { 488 @Override 489 public void onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses) { 490 try { 491 logl("onThrottleStatusChanged: " + throttleStatuses); 492 if (mIQualifiedNetworksService != null) { 493 mIQualifiedNetworksService.reportThrottleStatusChanged( 494 mPhone.getPhoneId(), throttleStatuses); 495 } 496 } catch (Exception ex) { 497 loge("onThrottleStatusChanged: ", ex); 498 } 499 } 500 }); 501 mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); 502 mDataConfigManager.registerCallback( 503 new DataConfigManager.DataConfigManagerCallback(this::post) { 504 @Override 505 public void onDeviceConfigChanged() { 506 mApnTypeToQnsChangeNetworkCounter.clear(); 507 } 508 }); 509 }); 510 } 511 } 512 513 /** 514 * Trigger the anomaly report with the specified UUID. 515 * 516 * @param anomalyMsg Description of the event 517 * @param uuid UUID associated with that event 518 */ reportAnomaly(@onNull String anomalyMsg, @NonNull String uuid)519 private void reportAnomaly(@NonNull String anomalyMsg, @NonNull String uuid) { 520 logl(anomalyMsg); 521 AnomalyReporter.reportAnomaly(UUID.fromString(uuid), anomalyMsg, mPhone.getCarrierId()); 522 } 523 524 /** 525 * Find the qualified network service from configuration and binds to it. It reads the 526 * configuration from carrier config if it exists. If not, read it from resources. 527 */ bindQualifiedNetworksService()528 private void bindQualifiedNetworksService() { 529 post(() -> { 530 Intent intent = null; 531 String packageName = getQualifiedNetworksServicePackageName(); 532 String className = getQualifiedNetworksServiceClassName(); 533 534 if (DBG) log("Qualified network service package = " + packageName); 535 if (TextUtils.isEmpty(packageName)) { 536 loge("Can't find the binding package"); 537 return; 538 } 539 540 if (TextUtils.isEmpty(className)) { 541 intent = new Intent(QualifiedNetworksService.QUALIFIED_NETWORKS_SERVICE_INTERFACE); 542 intent.setPackage(packageName); 543 } else { 544 ComponentName cm = new ComponentName(packageName, className); 545 intent = new Intent(QualifiedNetworksService.QUALIFIED_NETWORKS_SERVICE_INTERFACE) 546 .setComponent(cm); 547 } 548 549 if (TextUtils.equals(packageName, mTargetBindingPackageName)) { 550 if (DBG) log("Service " + packageName + " already bound or being bound."); 551 return; 552 } 553 554 if (mIQualifiedNetworksService != null 555 && mIQualifiedNetworksService.asBinder().isBinderAlive()) { 556 // Remove the network availability updater and then unbind the service. 557 try { 558 mIQualifiedNetworksService.removeNetworkAvailabilityProvider( 559 mPhone.getPhoneId()); 560 } catch (RemoteException e) { 561 loge("Cannot remove network availability updater. " + e); 562 } 563 564 mPhone.getContext().unbindService(mServiceConnection); 565 } 566 567 try { 568 mServiceConnection = new QualifiedNetworksServiceConnection(); 569 log("bind to " + packageName); 570 if (!mPhone.getContext().bindService(intent, mServiceConnection, 571 Context.BIND_AUTO_CREATE)) { 572 loge("Cannot bind to the qualified networks service."); 573 return; 574 } 575 mTargetBindingPackageName = packageName; 576 } catch (Exception e) { 577 loge("Cannot bind to the qualified networks service. Exception: " + e); 578 } 579 }); 580 } 581 582 /** 583 * Get the qualified network service package. 584 * 585 * @return package name of the qualified networks service package. Return empty string when in 586 * legacy mode (i.e. Dedicated IWLAN data/network service is not supported). 587 */ getQualifiedNetworksServicePackageName()588 private String getQualifiedNetworksServicePackageName() { 589 // Read package name from the resource 590 String packageName = mPhone.getContext().getResources().getString( 591 com.android.internal.R.string.config_qualified_networks_service_package); 592 593 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); 594 595 if (b != null) { 596 // If carrier config overrides it, use the one from carrier config 597 String carrierConfigPackageName = b.getString(CarrierConfigManager 598 .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING); 599 if (!TextUtils.isEmpty(carrierConfigPackageName)) { 600 if (DBG) log("Found carrier config override " + carrierConfigPackageName); 601 packageName = carrierConfigPackageName; 602 } 603 } 604 605 return packageName; 606 } 607 608 /** 609 * Get the qualified network service class name. 610 * 611 * @return class name of the qualified networks service package. 612 */ getQualifiedNetworksServiceClassName()613 private String getQualifiedNetworksServiceClassName() { 614 // Read package name from the resource 615 String className = mPhone.getContext().getResources().getString( 616 com.android.internal.R.string.config_qualified_networks_service_class); 617 618 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); 619 620 if (b != null) { 621 // If carrier config overrides it, use the one from carrier config 622 String carrierConfigClassName = b.getString(CarrierConfigManager 623 .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING); 624 if (!TextUtils.isEmpty(carrierConfigClassName)) { 625 if (DBG) log("Found carrier config override " + carrierConfigClassName); 626 className = carrierConfigClassName; 627 } 628 } 629 630 return className; 631 } 632 getQualifiedNetworksList()633 private @NonNull List<QualifiedNetworks> getQualifiedNetworksList() { 634 List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>(); 635 for (int i = 0; i < mAvailableNetworks.size(); i++) { 636 qualifiedNetworksList.add(new QualifiedNetworks(mAvailableNetworks.keyAt(i), 637 mAvailableNetworks.valueAt(i))); 638 } 639 640 return qualifiedNetworksList; 641 } 642 643 /** 644 * Register for qualified networks changed event. 645 * 646 * @param h The target to post the event message to. 647 * @param what The event. 648 */ registerForQualifiedNetworksChanged(Handler h, int what)649 public void registerForQualifiedNetworksChanged(Handler h, int what) { 650 if (h != null) { 651 Registrant r = new Registrant(h, what, null); 652 mQualifiedNetworksChangedRegistrants.add(r); 653 654 // Notify for the first time if there is already something in the available network 655 // list. 656 if (mAvailableNetworks.size() != 0) { 657 r.notifyResult(getQualifiedNetworksList()); 658 } 659 } 660 } 661 662 /** 663 * @return {@code true} if the device operates in legacy mode, otherwise {@code false}. 664 */ isInLegacyMode()665 public boolean isInLegacyMode() { 666 // Get IWLAN operation mode from the system property. If the system property is configured 667 // to default or not configured, the mode is tied to IRadio version. For 1.4 or above, it's 668 // AP-assisted mode, for 1.3 or below, it's legacy mode. 669 String mode = SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE); 670 671 if (mode.equals(IWLAN_OPERATION_MODE_AP_ASSISTED)) { 672 return false; 673 } else if (mode.equals(IWLAN_OPERATION_MODE_LEGACY)) { 674 return true; 675 } 676 677 return mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4); 678 } 679 680 /** 681 * @return The available transports. Note that on legacy devices, the only available transport 682 * would be WWAN only. If the device is configured as AP-assisted mode, the available transport 683 * will always be WWAN and WLAN (even if the device is not camped on IWLAN). 684 * See {@link #isInLegacyMode()} for mode details. 685 */ getAvailableTransports()686 public synchronized @NonNull int[] getAvailableTransports() { 687 return mAvailableTransports; 688 } 689 690 /** 691 * Get the transport based on the network capability. 692 * 693 * @param netCap The network capability. 694 * @return The transport type. 695 */ getCurrentTransportByNetworkCapability(@etCapability int netCap)696 public @TransportType int getCurrentTransportByNetworkCapability(@NetCapability int netCap) { 697 return getCurrentTransport(DataUtils.networkCapabilityToApnType(netCap)); 698 } 699 700 /** 701 * Get the transport based on the APN type. 702 * 703 * @param apnType APN type 704 * @return The transport type 705 */ 706 // TODO: Remove this after TransportManager is removed. getCurrentTransport(@pnType int apnType)707 public @TransportType int getCurrentTransport(@ApnType int apnType) { 708 // In legacy mode, always route to cellular. 709 if (isInLegacyMode()) { 710 return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 711 } 712 713 // If we can't find the corresponding transport, always route to cellular. 714 return mCurrentTransports.get(apnType) == null 715 ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mCurrentTransports.get(apnType); 716 } 717 718 /** 719 * Set the current transport of a network capability. 720 * 721 * @param netCap The network capability. 722 * @param transport The transport. 723 */ setCurrentTransportByNetworkCapability(@etCapability int netCap, @TransportType int transport)724 public void setCurrentTransportByNetworkCapability(@NetCapability int netCap, 725 @TransportType int transport) { 726 setCurrentTransport(DataUtils.networkCapabilityToApnType(netCap), transport); 727 } 728 729 /** 730 * Set the current transport of apn type. 731 * 732 * @param apnType The APN type 733 * @param transport The transport. 734 */ 735 // TODO: Remove this after TransportManager is removed. setCurrentTransport(@pnType int apnType, @TransportType int transport)736 public void setCurrentTransport(@ApnType int apnType, @TransportType int transport) { 737 Integer previousTransport = mCurrentTransports.put(apnType, transport); 738 if (previousTransport == null || previousTransport != transport) { 739 logl("setCurrentTransport: apnType=" + ApnSetting.getApnTypeString(apnType) 740 + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)); 741 } 742 } 743 getTransportFromAccessNetwork(int accessNetwork)744 private static @TransportType int getTransportFromAccessNetwork(int accessNetwork) { 745 return accessNetwork == AccessNetworkType.IWLAN 746 ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN 747 : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 748 } 749 setPreferredTransports(@onNull List<QualifiedNetworks> networksList)750 private void setPreferredTransports(@NonNull List<QualifiedNetworks> networksList) { 751 for (QualifiedNetworks networks : networksList) { 752 if (networks.qualifiedNetworks.length > 0) { 753 int transport = getTransportFromAccessNetwork(networks.qualifiedNetworks[0]); 754 if (getPreferredTransport(networks.apnType) != transport) { 755 mPreferredTransports.put(networks.apnType, transport); 756 mAccessNetworksManagerCallbacks.forEach(callback -> 757 callback.invokeFromExecutor(() -> 758 callback.onPreferredTransportChanged(DataUtils 759 .apnTypeToNetworkCapability(networks.apnType)))); 760 logl("setPreferredTransports: apnType=" 761 + ApnSetting.getApnTypeString(networks.apnType) + ", transport=" 762 + AccessNetworkConstants.transportTypeToString(transport)); 763 } 764 } 765 } 766 } 767 768 /** 769 * Get the preferred transport. 770 * 771 * @param apnType APN type 772 * @return The preferred transport. 773 */ getPreferredTransport(@pnType int apnType)774 public @TransportType int getPreferredTransport(@ApnType int apnType) { 775 // In legacy mode, always preferred on cellular. 776 if (isInLegacyMode()) { 777 return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 778 } 779 780 return mPreferredTransports.get(apnType) == null 781 ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mPreferredTransports.get(apnType); 782 } 783 784 /** 785 * Get the preferred transport by network capability. 786 * 787 * @param networkCapability The network capability. (Note that only APN-type capabilities are 788 * supported. 789 * @return The preferred transport. 790 */ getPreferredTransportByNetworkCapability( @etCapability int networkCapability)791 public @TransportType int getPreferredTransportByNetworkCapability( 792 @NetCapability int networkCapability) { 793 int apnType = DataUtils.networkCapabilityToApnType(networkCapability); 794 // For non-APN type capabilities, always route to WWAN. 795 if (apnType == ApnSetting.TYPE_NONE) { 796 return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 797 } 798 return getPreferredTransport(apnType); 799 } 800 801 /** 802 * Check if there is any APN type's current transport is on IWLAN. 803 * 804 * @return {@code true} if there is any APN is on IWLAN, otherwise {@code false}. 805 */ isAnyApnOnIwlan()806 public boolean isAnyApnOnIwlan() { 807 for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { 808 if (mPhone.isUsingNewDataStack()) { 809 if (getPreferredTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 810 return true; 811 } 812 } else { 813 if (getCurrentTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 814 return true; 815 } 816 } 817 } 818 return false; 819 } 820 821 /** 822 * Unregister for qualified networks changed event. 823 * 824 * @param h The handler 825 */ unregisterForQualifiedNetworksChanged(Handler h)826 public void unregisterForQualifiedNetworksChanged(Handler h) { 827 if (h != null) { 828 mQualifiedNetworksChangedRegistrants.remove(h); 829 } 830 } 831 832 /** 833 * Register the callback for receiving information from {@link AccessNetworksManager}. 834 * 835 * @param callback The callback. 836 */ registerCallback(@onNull AccessNetworksManagerCallback callback)837 public void registerCallback(@NonNull AccessNetworksManagerCallback callback) { 838 mAccessNetworksManagerCallbacks.add(callback); 839 } 840 841 /** 842 * Unregister the callback which was previously registered through 843 * {@link #registerCallback(AccessNetworksManagerCallback)}. 844 * 845 * @param callback The callback to unregister. 846 */ unregisterCallback(@onNull AccessNetworksManagerCallback callback)847 public void unregisterCallback(@NonNull AccessNetworksManagerCallback callback) { 848 mAccessNetworksManagerCallbacks.remove(callback); 849 } 850 log(String s)851 private void log(String s) { 852 Rlog.d(mLogTag, s); 853 } 854 loge(String s)855 private void loge(String s) { 856 Rlog.e(mLogTag, s); 857 } 858 loge(String s, Exception ex)859 private void loge(String s, Exception ex) { 860 Rlog.e(mLogTag, s, ex); 861 } 862 logl(String s)863 private void logl(String s) { 864 log(s); 865 mLocalLog.log(s); 866 } 867 868 /** 869 * Dump the state of access networks manager 870 * 871 * @param fd File descriptor 872 * @param printWriter Print writer 873 * @param args Arguments 874 */ dump(FileDescriptor fd, PrintWriter printWriter, String[] args)875 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 876 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 877 pw.println(AccessNetworksManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":"); 878 pw.increaseIndent(); 879 pw.println("current transports="); 880 pw.increaseIndent(); 881 for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { 882 pw.println(ApnSetting.getApnTypeString(apnType) 883 + ": " + AccessNetworkConstants.transportTypeToString( 884 getCurrentTransport(apnType))); 885 } 886 pw.decreaseIndent(); 887 pw.println("preferred transports="); 888 pw.increaseIndent(); 889 for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { 890 pw.println(ApnSetting.getApnTypeString(apnType) 891 + ": " + AccessNetworkConstants.transportTypeToString( 892 getPreferredTransport(apnType))); 893 } 894 895 pw.decreaseIndent(); 896 pw.println("isInLegacy=" + isInLegacyMode()); 897 pw.println("IWLAN operation mode=" 898 + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE)); 899 pw.println("Local logs="); 900 pw.increaseIndent(); 901 mLocalLog.dump(fd, pw, args); 902 pw.decreaseIndent(); 903 pw.decreaseIndent(); 904 pw.flush(); 905 } 906 } 907