• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.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