• 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.dataconnection;
18 
19 import android.annotation.Nullable;
20 import android.os.Handler;
21 import android.os.Message;
22 import android.os.RegistrantList;
23 import android.telephony.AccessNetworkConstants;
24 import android.telephony.Annotation.ApnType;
25 import android.telephony.CarrierConfigManager;
26 import android.telephony.data.ApnSetting;
27 import android.util.LocalLog;
28 import android.util.SparseIntArray;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 import com.android.internal.telephony.Phone;
32 import com.android.internal.telephony.data.AccessNetworksManager;
33 import com.android.internal.telephony.data.TelephonyNetworkFactory;
34 import com.android.telephony.Rlog;
35 
36 import java.util.concurrent.TimeUnit;
37 
38 /**
39  * This class represents the transport manager which manages available transports (i.e. WWAN or
40  * WLAN) and determine the correct transport for {@link TelephonyNetworkFactory} to handle the data
41  * requests.
42  *
43  * The device can operate in the following modes, which is stored in the system properties
44  * ro.telephony.iwlan_operation_mode. If the system properties is missing, then it's tied to
45  * IRadio version. For 1.4 or above, it's AP-assisted mdoe. For 1.3 or below, it's legacy mode.
46  *
47  * Legacy mode:
48  *      Frameworks send all data requests to the default data service, which is the cellular data
49  *      service. IWLAN should be still reported as a RAT on cellular network service.
50  *
51  * AP-assisted mode:
52  *      IWLAN is handled by IWLAN data service extending {@link android.telephony.data.DataService},
53  *      IWLAN network service extending {@link android.telephony.NetworkService}, and qualified
54  *      network service extending {@link android.telephony.data.QualifiedNetworksService}.
55  *
56  *      The following settings for service package name need to be configured properly for
57  *      frameworks to bind.
58  *
59  *      Package name of data service:
60  *          The resource overlay 'config_wlan_data_service_package' or,
61  *          the carrier config
62  *          {@link CarrierConfigManager#KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}.
63  *          The carrier config takes precedence over the resource overlay if both exist.
64  *
65  *      Package name of network service
66  *          The resource overlay 'config_wlan_network_service_package' or
67  *          the carrier config
68  *          {@link CarrierConfigManager#KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}.
69  *          The carrier config takes precedence over the resource overlay if both exist.
70  *
71  *      Package name of qualified network service
72  *          The resource overlay 'config_qualified_networks_service_package' or
73  *          the carrier config
74  *          {@link CarrierConfigManager#
75  *          KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING}.
76  *          The carrier config takes precedence over the resource overlay if both exist.
77  */
78 public class TransportManager extends Handler {
79     private final String mLogTag;
80 
81     private static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 1;
82 
83     private static final int EVENT_EVALUATE_TRANSPORT_PREFERENCE = 2;
84 
85     // Delay the re-evaluation if transport fall back. QNS will need to quickly change the
86     // preference back to the original transport to avoid another handover request.
87     private static final long FALL_BACK_REEVALUATE_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(3);
88 
89     private final Phone mPhone;
90 
91     private final LocalLog mLocalLog = new LocalLog(64);
92 
93     @Nullable
94     private AccessNetworksManager mAccessNetworksManager;
95 
96     /**
97      * The pending handover list. This is a list of APNs that are being handover to the new
98      * transport. The entry will be removed once handover is completed. The key
99      * is the APN type, and the value is the target transport that the APN is handovered to.
100      */
101     private final SparseIntArray mPendingHandoverApns;
102 
103     /**
104      * The registrants for listening data handover needed events.
105      */
106     private final RegistrantList mHandoverNeededEventRegistrants;
107 
108     /**
109      * Handover parameters
110      */
111     @VisibleForTesting
112     public static final class HandoverParams {
113         /**
114          * The callback for handover complete.
115          */
116         public interface HandoverCallback {
117             /**
118              * Called when handover is completed.
119              *
120              * @param success {@true} if handover succeeded, otherwise failed.
121              * @param fallback {@true} if handover failed, the data connection fallback to the
122              * original transport
123              */
onCompleted(boolean success, boolean fallback)124             void onCompleted(boolean success, boolean fallback);
125         }
126 
127         public final @ApnType int apnType;
128         public final int targetTransport;
129         public final HandoverCallback callback;
130 
131         @VisibleForTesting
HandoverParams(int apnType, int targetTransport, HandoverCallback callback)132         public HandoverParams(int apnType, int targetTransport, HandoverCallback callback) {
133             this.apnType = apnType;
134             this.targetTransport = targetTransport;
135             this.callback = callback;
136         }
137     }
138 
TransportManager(Phone phone)139     public TransportManager(Phone phone) {
140         mPhone = phone;
141         mPendingHandoverApns = new SparseIntArray();
142         mHandoverNeededEventRegistrants = new RegistrantList();
143         mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId();
144         mAccessNetworksManager = mPhone.getAccessNetworksManager();
145         mAccessNetworksManager.registerForQualifiedNetworksChanged(this,
146                 EVENT_QUALIFIED_NETWORKS_CHANGED);
147     }
148 
149     @Override
handleMessage(Message msg)150     public void handleMessage(Message msg) {
151         switch (msg.what) {
152             case EVENT_QUALIFIED_NETWORKS_CHANGED:
153                 if (!hasMessages(EVENT_EVALUATE_TRANSPORT_PREFERENCE)) {
154                     sendEmptyMessage(EVENT_EVALUATE_TRANSPORT_PREFERENCE);
155                 }
156                 break;
157             case EVENT_EVALUATE_TRANSPORT_PREFERENCE:
158                 evaluateTransportPreference();
159                 break;
160             default:
161                 loge("Unexpected event " + msg.what);
162                 break;
163         }
164     }
165 
166     /**
167      * Set the current transport of apn type.
168      *
169      * @param apnType The APN type
170      * @param transport The transport. Must be WWAN or WLAN.
171      */
setCurrentTransport(@pnType int apnType, int transport)172     private synchronized void setCurrentTransport(@ApnType int apnType, int transport) {
173         mAccessNetworksManager.setCurrentTransport(apnType, transport);
174     }
175 
isHandoverPending()176     private boolean isHandoverPending() {
177         return mPendingHandoverApns.size() > 0;
178     }
179 
180     /**
181      * Evaluate the preferred transport for each APN type to see if handover is needed.
182      */
evaluateTransportPreference()183     private void evaluateTransportPreference() {
184         // Simultaneously handover is not supported today. Preference will be re-evaluated after
185         // handover completed.
186         if (isHandoverPending()) return;
187         logl("evaluateTransportPreference");
188         for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) {
189             int targetTransport = mAccessNetworksManager.getPreferredTransport(apnType);
190             if (targetTransport != mAccessNetworksManager.getCurrentTransport(apnType)) {
191                 logl("Handover started for APN type: "
192                         + ApnSetting.getApnTypeString(apnType)
193                         + ", target transport: "
194                         + AccessNetworkConstants.transportTypeToString(targetTransport));
195                 mPendingHandoverApns.put(apnType, targetTransport);
196                 mHandoverNeededEventRegistrants.notifyResult(
197                         new HandoverParams(apnType, targetTransport,
198                                 (success, fallback) -> {
199                                     // The callback for handover completed.
200                                     if (success) {
201                                         logl("Handover succeeded for APN type "
202                                                 + ApnSetting.getApnTypeString(apnType));
203                                     } else {
204                                         logl("APN type "
205                                                 + ApnSetting.getApnTypeString(apnType)
206                                                 + " handover to "
207                                                 + AccessNetworkConstants.transportTypeToString(
208                                                 targetTransport) + " failed"
209                                                 + ", fallback=" + fallback);
210                                     }
211 
212                                     long delay = 0;
213                                     if (fallback) {
214                                         // No need to change the preference because we should
215                                         // fallback. Re-evaluate after few seconds to give QNS
216                                         // some time to change the preference back to the original
217                                         // transport.
218                                         delay = FALL_BACK_REEVALUATE_DELAY_MILLIS;
219                                     } else {
220                                         // If handover succeeds or failed without falling back
221                                         // to the original transport, we should move to the new
222                                         // transport (even if it is failed).
223                                         setCurrentTransport(apnType, targetTransport);
224                                     }
225                                     mPendingHandoverApns.delete(apnType);
226                                     sendEmptyMessageDelayed(EVENT_EVALUATE_TRANSPORT_PREFERENCE,
227                                             delay);
228                                 }));
229 
230                 // Return here instead of processing the next APN type. The next APN type for
231                 // handover will be evaluate again once current handover is completed.
232                 return;
233             }
234         }
235     }
236 
237     /**
238      * Register for data handover needed event
239      *
240      * @param h The handler of the event
241      * @param what The id of the event
242      */
registerForHandoverNeededEvent(Handler h, int what)243     public void registerForHandoverNeededEvent(Handler h, int what) {
244         if (h != null) {
245             mHandoverNeededEventRegistrants.addUnique(h, what, null);
246         }
247     }
248 
249     /**
250      * Unregister for data handover needed event
251      *
252      * @param h The handler
253      */
unregisterForHandoverNeededEvent(Handler h)254     public void unregisterForHandoverNeededEvent(Handler h) {
255         mHandoverNeededEventRegistrants.remove(h);
256     }
257 
258     /**
259      * Registers the data throttler with DcTracker.
260      */
registerDataThrottler(DataThrottler dataThrottler)261     public void registerDataThrottler(DataThrottler dataThrottler) {
262         if (mAccessNetworksManager != null) {
263             mAccessNetworksManager.registerDataThrottler(dataThrottler);
264         }
265     }
266 
logl(String s)267     private void logl(String s) {
268         log(s);
269         mLocalLog.log(s);
270     }
271 
log(String s)272     private void log(String s) {
273         Rlog.d(mLogTag, s);
274     }
275 
loge(String s)276     private void loge(String s) {
277         Rlog.e(mLogTag, s);
278     }
279 }
280