1 /* 2 * Copyright (C) 2016 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 static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 20 21 import android.net.NetworkCapabilities; 22 import android.net.NetworkFactory; 23 import android.net.NetworkRequest; 24 import android.net.TelephonyNetworkSpecifier; 25 import android.os.AsyncResult; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.Looper; 29 import android.os.Message; 30 import android.telephony.AccessNetworkConstants; 31 import android.telephony.Annotation.ApnType; 32 import android.telephony.SubscriptionManager; 33 import android.telephony.data.ApnSetting; 34 import android.util.LocalLog; 35 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.internal.telephony.Phone; 38 import com.android.internal.telephony.PhoneSwitcher; 39 import com.android.internal.telephony.SubscriptionController; 40 import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; 41 import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; 42 import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams; 43 import com.android.internal.util.IndentingPrintWriter; 44 import com.android.telephony.Rlog; 45 46 import java.io.FileDescriptor; 47 import java.io.PrintWriter; 48 import java.util.HashMap; 49 import java.util.Map; 50 51 public class TelephonyNetworkFactory extends NetworkFactory { 52 public final String LOG_TAG; 53 protected static final boolean DBG = true; 54 55 private static final int REQUEST_LOG_SIZE = 40; 56 57 private static final int ACTION_NO_OP = 0; 58 private static final int ACTION_REQUEST = 1; 59 private static final int ACTION_RELEASE = 2; 60 61 private static final int TELEPHONY_NETWORK_SCORE = 50; 62 63 @VisibleForTesting 64 public static final int EVENT_ACTIVE_PHONE_SWITCH = 1; 65 @VisibleForTesting 66 public static final int EVENT_SUBSCRIPTION_CHANGED = 2; 67 private static final int EVENT_NETWORK_REQUEST = 3; 68 private static final int EVENT_NETWORK_RELEASE = 4; 69 private static final int EVENT_DATA_HANDOVER_NEEDED = 5; 70 private static final int EVENT_DATA_HANDOVER_COMPLETED = 6; 71 72 private final PhoneSwitcher mPhoneSwitcher; 73 private final SubscriptionController mSubscriptionController; 74 private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE); 75 76 // Key: network request. Value: the transport of DcTracker it applies to, 77 // AccessNetworkConstants.TRANSPORT_TYPE_INVALID if not applied. 78 private final Map<NetworkRequest, Integer> mNetworkRequests = new HashMap<>(); 79 80 private final Map<Message, HandoverParams> mPendingHandovers = new HashMap<>(); 81 82 private final Phone mPhone; 83 84 private final TransportManager mTransportManager; 85 86 private int mSubscriptionId; 87 88 @VisibleForTesting 89 public final Handler mInternalHandler; 90 91 TelephonyNetworkFactory(Looper looper, Phone phone)92 public TelephonyNetworkFactory(Looper looper, Phone phone) { 93 super(looper, phone.getContext(), "TelephonyNetworkFactory[" + phone.getPhoneId() 94 + "]", null); 95 mPhone = phone; 96 mTransportManager = mPhone.getTransportManager(); 97 mInternalHandler = new InternalHandler(looper); 98 99 mSubscriptionController = SubscriptionController.getInstance(); 100 101 setCapabilityFilter(makeNetworkFilter(mSubscriptionController, mPhone.getPhoneId())); 102 setScoreFilter(TELEPHONY_NETWORK_SCORE); 103 104 mPhoneSwitcher = PhoneSwitcher.getInstance(); 105 LOG_TAG = "TelephonyNetworkFactory[" + mPhone.getPhoneId() + "]"; 106 107 mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH, 108 null); 109 mTransportManager.registerForHandoverNeededEvent(mInternalHandler, 110 EVENT_DATA_HANDOVER_NEEDED); 111 112 mSubscriptionId = INVALID_SUBSCRIPTION_ID; 113 SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener( 114 mSubscriptionsChangedListener); 115 116 register(); 117 } 118 119 private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener = 120 new SubscriptionManager.OnSubscriptionsChangedListener() { 121 @Override 122 public void onSubscriptionsChanged() { 123 mInternalHandler.sendEmptyMessage(EVENT_SUBSCRIPTION_CHANGED); 124 } 125 }; 126 makeNetworkFilter(SubscriptionController subscriptionController, int phoneId)127 private NetworkCapabilities makeNetworkFilter(SubscriptionController subscriptionController, 128 int phoneId) { 129 final int subscriptionId = subscriptionController.getSubIdUsingPhoneId(phoneId); 130 return makeNetworkFilter(subscriptionId); 131 } 132 makeNetworkFilter(int subscriptionId)133 private NetworkCapabilities makeNetworkFilter(int subscriptionId) { 134 NetworkCapabilities nc = new NetworkCapabilities(); 135 nc.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 136 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); 137 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); 138 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); 139 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); 140 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); 141 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); 142 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); 143 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_RCS); 144 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); 145 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); 146 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 147 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 148 nc.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() 149 .setSubscriptionId(subscriptionId).build()); 150 return nc; 151 } 152 153 private class InternalHandler extends Handler { InternalHandler(Looper looper)154 public InternalHandler(Looper looper) { 155 super(looper); 156 } 157 158 @Override handleMessage(Message msg)159 public void handleMessage(Message msg) { 160 switch (msg.what) { 161 case EVENT_ACTIVE_PHONE_SWITCH: { 162 onActivePhoneSwitch(); 163 break; 164 } 165 case EVENT_SUBSCRIPTION_CHANGED: { 166 onSubIdChange(); 167 break; 168 } 169 case EVENT_NETWORK_REQUEST: { 170 onNeedNetworkFor(msg); 171 break; 172 } 173 case EVENT_NETWORK_RELEASE: { 174 onReleaseNetworkFor(msg); 175 break; 176 } 177 case EVENT_DATA_HANDOVER_NEEDED: { 178 AsyncResult ar = (AsyncResult) msg.obj; 179 HandoverParams handoverParams = (HandoverParams) ar.result; 180 onDataHandoverNeeded(handoverParams.apnType, handoverParams.targetTransport, 181 handoverParams); 182 break; 183 } 184 case EVENT_DATA_HANDOVER_COMPLETED: { 185 Bundle bundle = msg.getData(); 186 int requestType = bundle.getInt(DcTracker.DATA_COMPLETE_MSG_EXTRA_REQUEST_TYPE); 187 if (requestType == DcTracker.REQUEST_TYPE_HANDOVER) { 188 NetworkRequest nr = bundle.getParcelable( 189 DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST); 190 boolean success = bundle.getBoolean( 191 DcTracker.DATA_COMPLETE_MSG_EXTRA_SUCCESS); 192 int transport = bundle.getInt( 193 DcTracker.DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE); 194 boolean fallback = bundle.getBoolean( 195 DcTracker.DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK); 196 HandoverParams handoverParams = mPendingHandovers.remove(msg); 197 if (handoverParams != null) { 198 onDataHandoverSetupCompleted(nr, success, transport, fallback, 199 handoverParams); 200 } else { 201 logl("Handover completed but cannot find handover entry!"); 202 } 203 } 204 break; 205 } 206 } 207 } 208 } 209 getTransportTypeFromNetworkRequest(NetworkRequest networkRequest)210 private int getTransportTypeFromNetworkRequest(NetworkRequest networkRequest) { 211 int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); 212 return mTransportManager.getCurrentTransport(apnType); 213 } 214 requestNetworkInternal(NetworkRequest networkRequest, @RequestNetworkType int requestType, int transport, Message onCompleteMsg)215 private void requestNetworkInternal(NetworkRequest networkRequest, 216 @RequestNetworkType int requestType, 217 int transport, Message onCompleteMsg) { 218 if (mPhone.getDcTracker(transport) != null) { 219 mPhone.getDcTracker(transport).requestNetwork(networkRequest, requestType, 220 onCompleteMsg); 221 } 222 } 223 releaseNetworkInternal(NetworkRequest networkRequest, @ReleaseNetworkType int releaseType, int transport)224 private void releaseNetworkInternal(NetworkRequest networkRequest, 225 @ReleaseNetworkType int releaseType, 226 int transport) { 227 if (mPhone.getDcTracker(transport) != null) { 228 mPhone.getDcTracker(transport).releaseNetwork(networkRequest, releaseType); 229 } 230 } 231 getAction(boolean wasActive, boolean isActive)232 private static int getAction(boolean wasActive, boolean isActive) { 233 if (!wasActive && isActive) { 234 return ACTION_REQUEST; 235 } else if (wasActive && !isActive) { 236 return ACTION_RELEASE; 237 } else { 238 return ACTION_NO_OP; 239 } 240 } 241 242 // apply or revoke requests if our active-ness changes onActivePhoneSwitch()243 private void onActivePhoneSwitch() { 244 for (HashMap.Entry<NetworkRequest, Integer> entry : mNetworkRequests.entrySet()) { 245 NetworkRequest networkRequest = entry.getKey(); 246 boolean applied = entry.getValue() != AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 247 248 boolean shouldApply = mPhoneSwitcher.shouldApplyNetworkRequest( 249 networkRequest, mPhone.getPhoneId()); 250 251 int action = getAction(applied, shouldApply); 252 if (action == ACTION_NO_OP) continue; 253 254 logl("onActivePhoneSwitch: " + ((action == ACTION_REQUEST) 255 ? "Requesting" : "Releasing") + " network request " + networkRequest); 256 int transportType = getTransportTypeFromNetworkRequest(networkRequest); 257 if (action == ACTION_REQUEST) { 258 requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, 259 getTransportTypeFromNetworkRequest(networkRequest), null); 260 } else if (action == ACTION_RELEASE) { 261 releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_DETACH, 262 getTransportTypeFromNetworkRequest(networkRequest)); 263 } 264 265 mNetworkRequests.put(networkRequest, 266 shouldApply ? transportType : AccessNetworkConstants.TRANSPORT_TYPE_INVALID); 267 } 268 } 269 270 // watch for phone->subId changes, reapply new filter and let 271 // that flow through to apply/revoke of requests onSubIdChange()272 private void onSubIdChange() { 273 final int newSubscriptionId = mSubscriptionController.getSubIdUsingPhoneId( 274 mPhone.getPhoneId()); 275 if (mSubscriptionId != newSubscriptionId) { 276 if (DBG) log("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId); 277 mSubscriptionId = newSubscriptionId; 278 setCapabilityFilter(makeNetworkFilter(mSubscriptionId)); 279 } 280 } 281 282 @Override needNetworkFor(NetworkRequest networkRequest, int score)283 public void needNetworkFor(NetworkRequest networkRequest, int score) { 284 Message msg = mInternalHandler.obtainMessage(EVENT_NETWORK_REQUEST); 285 msg.obj = networkRequest; 286 msg.sendToTarget(); 287 } 288 onNeedNetworkFor(Message msg)289 private void onNeedNetworkFor(Message msg) { 290 NetworkRequest networkRequest = (NetworkRequest) msg.obj; 291 boolean shouldApply = mPhoneSwitcher.shouldApplyNetworkRequest( 292 networkRequest, mPhone.getPhoneId()); 293 294 mNetworkRequests.put(networkRequest, shouldApply 295 ? getTransportTypeFromNetworkRequest(networkRequest) 296 : AccessNetworkConstants.TRANSPORT_TYPE_INVALID); 297 298 logl("onNeedNetworkFor " + networkRequest + " shouldApply " + shouldApply); 299 300 if (shouldApply) { 301 requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, 302 getTransportTypeFromNetworkRequest(networkRequest), null); 303 } 304 } 305 306 @Override releaseNetworkFor(NetworkRequest networkRequest)307 public void releaseNetworkFor(NetworkRequest networkRequest) { 308 Message msg = mInternalHandler.obtainMessage(EVENT_NETWORK_RELEASE); 309 msg.obj = networkRequest; 310 msg.sendToTarget(); 311 } 312 onReleaseNetworkFor(Message msg)313 private void onReleaseNetworkFor(Message msg) { 314 NetworkRequest networkRequest = (NetworkRequest) msg.obj; 315 boolean applied = mNetworkRequests.get(networkRequest) 316 != AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 317 318 mNetworkRequests.remove(networkRequest); 319 320 logl("onReleaseNetworkFor " + networkRequest + " applied " + applied); 321 322 if (applied) { 323 int transport = getTransportTypeFromNetworkRequest(networkRequest); 324 releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, transport); 325 } 326 } 327 onDataHandoverNeeded(@pnType int apnType, int targetTransport, HandoverParams handoverParams)328 private void onDataHandoverNeeded(@ApnType int apnType, int targetTransport, 329 HandoverParams handoverParams) { 330 log("onDataHandoverNeeded: apnType=" + ApnSetting.getApnTypeString(apnType) 331 + ", target transport=" 332 + AccessNetworkConstants.transportTypeToString(targetTransport)); 333 if (mTransportManager.getCurrentTransport(apnType) == targetTransport) { 334 log("APN type " + ApnSetting.getApnTypeString(apnType) + " is already on " 335 + AccessNetworkConstants.transportTypeToString(targetTransport)); 336 return; 337 } 338 339 boolean handoverPending = false; 340 for (HashMap.Entry<NetworkRequest, Integer> entry : mNetworkRequests.entrySet()) { 341 NetworkRequest networkRequest = entry.getKey(); 342 int currentTransport = entry.getValue(); 343 boolean applied = currentTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 344 if (ApnContext.getApnTypeFromNetworkRequest(networkRequest) == apnType 345 && applied 346 && currentTransport != targetTransport) { 347 DcTracker dcTracker = mPhone.getDcTracker(currentTransport); 348 if (dcTracker != null) { 349 DataConnection dc = dcTracker.getDataConnectionByApnType( 350 ApnSetting.getApnTypeString(apnType)); 351 if (dc != null && (dc.isActive())) { 352 Message onCompleteMsg = mInternalHandler.obtainMessage( 353 EVENT_DATA_HANDOVER_COMPLETED); 354 onCompleteMsg.getData().putParcelable( 355 DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST, networkRequest); 356 mPendingHandovers.put(onCompleteMsg, handoverParams); 357 requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_HANDOVER, 358 targetTransport, onCompleteMsg); 359 log("Requested handover " + ApnSetting.getApnTypeString(apnType) + " to " 360 + AccessNetworkConstants.transportTypeToString(targetTransport)); 361 handoverPending = true; 362 } else { 363 // Request is there, but no actual data connection. In this case, just move 364 // the request to the new transport. 365 log("The network request is on transport " + AccessNetworkConstants 366 .transportTypeToString(currentTransport) + ", but no live data " 367 + "connection. Just move the request to transport " 368 + AccessNetworkConstants.transportTypeToString(targetTransport) 369 + ", dc=" + dc); 370 entry.setValue(targetTransport); 371 releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, 372 currentTransport); 373 requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, 374 targetTransport, null); 375 } 376 } else { 377 log("DcTracker on " + AccessNetworkConstants.transportTypeToString( 378 currentTransport) + " is not available."); 379 } 380 } 381 } 382 383 if (!handoverPending) { 384 log("No handover request pending. Handover process is now completed"); 385 handoverParams.callback.onCompleted(true, false); 386 } 387 } 388 onDataHandoverSetupCompleted(NetworkRequest networkRequest, boolean success, int targetTransport, boolean fallback, HandoverParams handoverParams)389 private void onDataHandoverSetupCompleted(NetworkRequest networkRequest, boolean success, 390 int targetTransport, boolean fallback, 391 HandoverParams handoverParams) { 392 log("onDataHandoverSetupCompleted: " + networkRequest + ", success=" + success 393 + ", targetTransport=" 394 + AccessNetworkConstants.transportTypeToString(targetTransport) 395 + ", fallback=" + fallback); 396 397 // At this point, handover setup has been completed on the target transport. 398 // If it succeeded, or it failed without falling back to the original transport, 399 // we should release the request from the original transport. 400 if (!fallback) { 401 int originTransport = (targetTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) 402 ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN 403 : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 404 int releaseType = success 405 ? DcTracker.RELEASE_TYPE_HANDOVER 406 // If handover fails, we need to tear down the existing connection, so the 407 // new data connection can be re-established on the new transport. If we leave 408 // the existing data connection in current transport, then DCT and qualified 409 // network service will be out of sync. Specifying release type to detach 410 // the transport is moved to the other transport, but network request is still 411 // there, connectivity service will not call unwanted to tear down the network. 412 // We need explicitly tear down the data connection here so the new data 413 // connection can be re-established on the other transport. 414 : DcTracker.RELEASE_TYPE_DETACH; 415 releaseNetworkInternal(networkRequest, releaseType, originTransport); 416 mNetworkRequests.put(networkRequest, targetTransport); 417 } 418 419 handoverParams.callback.onCompleted(success, fallback); 420 } 421 log(String s)422 protected void log(String s) { 423 Rlog.d(LOG_TAG, s); 424 } 425 logl(String s)426 protected void logl(String s) { 427 log(s); 428 mLocalLog.log(s); 429 } 430 dump(FileDescriptor fd, PrintWriter writer, String[] args)431 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 432 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 433 pw.println("Network Requests:"); 434 pw.increaseIndent(); 435 for (HashMap.Entry<NetworkRequest, Integer> entry : mNetworkRequests.entrySet()) { 436 NetworkRequest nr = entry.getKey(); 437 int transport = entry.getValue(); 438 pw.println(nr + (transport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID 439 ? (" applied on " + transport) : " not applied")); 440 } 441 mLocalLog.dump(fd, pw, args); 442 pw.decreaseIndent(); 443 } 444 } 445