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