1 /* 2 * Copyright 2020 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.google.android.iwlan; 18 19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 21 22 import android.content.Context; 23 import android.content.Intent; 24 import android.net.ConnectivityManager; 25 import android.net.LinkAddress; 26 import android.net.LinkProperties; 27 import android.net.Network; 28 import android.net.NetworkCapabilities; 29 import android.os.Handler; 30 import android.os.HandlerThread; 31 import android.os.IBinder; 32 import android.os.Looper; 33 import android.os.Message; 34 import android.support.annotation.GuardedBy; 35 import android.support.annotation.IntRange; 36 import android.support.annotation.NonNull; 37 import android.support.annotation.Nullable; 38 import android.telephony.AccessNetworkConstants.AccessNetworkType; 39 import android.telephony.DataFailCause; 40 import android.telephony.TelephonyManager; 41 import android.telephony.data.ApnSetting; 42 import android.telephony.data.DataCallResponse; 43 import android.telephony.data.DataProfile; 44 import android.telephony.data.DataService; 45 import android.telephony.data.DataServiceCallback; 46 import android.telephony.data.NetworkSliceInfo; 47 import android.telephony.data.TrafficDescriptor; 48 import android.util.Log; 49 50 import com.android.internal.annotations.VisibleForTesting; 51 52 import com.google.android.iwlan.epdg.EpdgSelector; 53 import com.google.android.iwlan.epdg.EpdgTunnelManager; 54 import com.google.android.iwlan.epdg.TunnelLinkProperties; 55 import com.google.android.iwlan.epdg.TunnelSetupRequest; 56 57 import java.io.FileDescriptor; 58 import java.io.PrintWriter; 59 import java.net.Inet4Address; 60 import java.net.Inet6Address; 61 import java.net.InetAddress; 62 import java.net.UnknownHostException; 63 import java.util.ArrayList; 64 import java.util.Calendar; 65 import java.util.Date; 66 import java.util.HashMap; 67 import java.util.List; 68 import java.util.LongSummaryStatistics; 69 import java.util.Map; 70 import java.util.concurrent.ConcurrentHashMap; 71 72 public class IwlanDataService extends DataService { 73 74 private static final String TAG = IwlanDataService.class.getSimpleName(); 75 private static Context mContext; 76 private IwlanNetworkMonitorCallback mNetworkMonitorCallback; 77 private HandlerThread mNetworkCallbackHandlerThread; 78 private static boolean sNetworkConnected = false; 79 private static Network sNetwork = null; 80 // TODO: Change this to a hashmap as there is only one provider per slot 81 private static List<IwlanDataServiceProvider> sIwlanDataServiceProviderList = 82 new ArrayList<IwlanDataServiceProvider>(); 83 84 @VisibleForTesting 85 enum Transport { 86 UNSPECIFIED_NETWORK, 87 MOBILE, 88 WIFI; 89 } 90 91 private static Transport sDefaultDataTransport = Transport.UNSPECIFIED_NETWORK; 92 93 enum LinkProtocolType { 94 UNKNOWN, 95 IPV4, 96 IPV6, 97 IPV4V6; 98 } 99 100 private static LinkProtocolType sLinkProtocolType = LinkProtocolType.UNKNOWN; 101 102 // TODO: see if network monitor callback impl can be shared between dataservice and 103 // networkservice 104 static class IwlanNetworkMonitorCallback extends ConnectivityManager.NetworkCallback { 105 106 /** Called when the framework connects and has declared a new network ready for use. */ 107 @Override onAvailable(Network network)108 public void onAvailable(Network network) { 109 Log.d(TAG, "onAvailable: " + network); 110 } 111 112 /** 113 * Called when the network is about to be lost, typically because there are no outstanding 114 * requests left for it. This may be paired with a {@link NetworkCallback#onAvailable} call 115 * with the new replacement network for graceful handover. This method is not guaranteed to 116 * be called before {@link NetworkCallback#onLost} is called, for example in case a network 117 * is suddenly disconnected. 118 */ 119 @Override onLosing(Network network, int maxMsToLive)120 public void onLosing(Network network, int maxMsToLive) { 121 Log.d(TAG, "onLosing: maxMsToLive: " + maxMsToLive + " network: " + network); 122 } 123 124 /** 125 * Called when a network disconnects or otherwise no longer satisfies this request or 126 * callback. 127 */ 128 @Override onLost(Network network)129 public void onLost(Network network) { 130 Log.d(TAG, "onLost: " + network); 131 IwlanDataService.setNetworkConnected(false, network, Transport.UNSPECIFIED_NETWORK); 132 } 133 134 /** Called when the network corresponding to this request changes {@link LinkProperties}. */ 135 @Override onLinkPropertiesChanged(Network network, LinkProperties linkProperties)136 public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { 137 Log.d(TAG, "onLinkPropertiesChanged: " + linkProperties); 138 if (isLinkProtocolTypeChanged(linkProperties)) { 139 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) { 140 dp.dnsPrefetchCheck(); 141 } 142 } 143 } 144 145 /** Called when access to the specified network is blocked or unblocked. */ 146 @Override onBlockedStatusChanged(Network network, boolean blocked)147 public void onBlockedStatusChanged(Network network, boolean blocked) { 148 // TODO: check if we need to handle this 149 Log.d(TAG, "onBlockedStatusChanged: " + network + " BLOCKED:" + blocked); 150 } 151 152 @Override onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities)153 public void onCapabilitiesChanged( 154 Network network, NetworkCapabilities networkCapabilities) { 155 // onCapabilitiesChanged is guaranteed to be called immediately after onAvailable per 156 // API 157 Log.d(TAG, "onCapabilitiesChanged: " + network + " " + networkCapabilities); 158 if (networkCapabilities != null) { 159 if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { 160 Log.d(TAG, "Network " + network + " connected using transport MOBILE"); 161 IwlanDataService.setNetworkConnected(true, network, Transport.MOBILE); 162 } else if (networkCapabilities.hasTransport(TRANSPORT_WIFI)) { 163 Log.d(TAG, "Network " + network + " connected using transport WIFI"); 164 IwlanDataService.setNetworkConnected(true, network, Transport.WIFI); 165 } else { 166 Log.w(TAG, "Network does not have cellular or wifi capability"); 167 } 168 } 169 } 170 } 171 172 @VisibleForTesting 173 class IwlanDataServiceProvider extends DataService.DataServiceProvider { 174 175 private static final int CALLBACK_TYPE_SETUP_DATACALL_COMPLETE = 1; 176 private static final int CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE = 2; 177 private static final int CALLBACK_TYPE_GET_DATACALL_LIST_COMPLETE = 3; 178 private final String SUB_TAG; 179 private final IwlanDataService mIwlanDataService; 180 private final IwlanTunnelCallback mIwlanTunnelCallback; 181 private HandlerThread mHandlerThread; 182 @VisibleForTesting Handler mHandler; 183 private boolean mWfcEnabled = false; 184 private boolean mCarrierConfigReady = false; 185 private EpdgSelector mEpdgSelector; 186 private IwlanDataTunnelStats mTunnelStats; 187 188 // apn to TunnelState 189 // Lock this at public entry and exit points if: 190 // 1) the function changes mTunnelStateForApn 191 // 2) Makes decisions based on contents of mTunnelStateForApn 192 @GuardedBy("mTunnelStateForApn") 193 private Map<String, TunnelState> mTunnelStateForApn = new ConcurrentHashMap<>(); 194 195 // Holds the state of a tunnel (for an APN) 196 @VisibleForTesting 197 class TunnelState { 198 199 // this should be ideally be based on path MTU discovery. 1280 is the minimum packet 200 // size ipv6 routers have to handle so setting it to 1280 is the safest approach. 201 // ideally it should be 1280 - tunnelling overhead ? 202 private static final int LINK_MTU = 203 1280; // TODO: need to substract tunnelling overhead? 204 static final int TUNNEL_DOWN = 1; 205 static final int TUNNEL_IN_BRINGUP = 2; 206 static final int TUNNEL_UP = 3; 207 static final int TUNNEL_IN_BRINGDOWN = 4; 208 static final int TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP = 5; 209 private DataServiceCallback dataServiceCallback; 210 private int mState; 211 private int mPduSessionId; 212 private TunnelLinkProperties mTunnelLinkProperties; 213 private boolean mIsHandover; 214 private Date mBringUpStateTime = null; 215 private Date mUpStateTime = null; 216 getPduSessionId()217 public int getPduSessionId() { 218 return mPduSessionId; 219 } 220 setPduSessionId(int mPduSessionId)221 public void setPduSessionId(int mPduSessionId) { 222 this.mPduSessionId = mPduSessionId; 223 } 224 getProtocolType()225 public int getProtocolType() { 226 return mProtocolType; 227 } 228 getLinkMtu()229 public int getLinkMtu() { 230 return LINK_MTU; // TODO: need to substract tunnelling overhead 231 } 232 setProtocolType(int protocolType)233 public void setProtocolType(int protocolType) { 234 mProtocolType = protocolType; 235 } 236 237 private int mProtocolType; // from DataProfile 238 getTunnelLinkProperties()239 public TunnelLinkProperties getTunnelLinkProperties() { 240 return mTunnelLinkProperties; 241 } 242 setTunnelLinkProperties(TunnelLinkProperties tunnelLinkProperties)243 public void setTunnelLinkProperties(TunnelLinkProperties tunnelLinkProperties) { 244 mTunnelLinkProperties = tunnelLinkProperties; 245 } 246 getDataServiceCallback()247 public DataServiceCallback getDataServiceCallback() { 248 return dataServiceCallback; 249 } 250 setDataServiceCallback(DataServiceCallback dataServiceCallback)251 public void setDataServiceCallback(DataServiceCallback dataServiceCallback) { 252 this.dataServiceCallback = dataServiceCallback; 253 } 254 TunnelState(DataServiceCallback callback)255 public TunnelState(DataServiceCallback callback) { 256 dataServiceCallback = callback; 257 mState = TUNNEL_DOWN; 258 } 259 getState()260 public int getState() { 261 return mState; 262 } 263 264 /** @param state (TunnelState.TUNNEL_DOWN|TUNNEL_UP|TUNNEL_DOWN) */ setState(int state)265 public void setState(int state) { 266 mState = state; 267 if (mState == TunnelState.TUNNEL_IN_BRINGUP) { 268 mBringUpStateTime = Calendar.getInstance().getTime(); 269 } 270 if (mState == TunnelState.TUNNEL_UP) { 271 mUpStateTime = Calendar.getInstance().getTime(); 272 } 273 } 274 setIsHandover(boolean isHandover)275 public void setIsHandover(boolean isHandover) { 276 mIsHandover = isHandover; 277 } 278 getIsHandover()279 public boolean getIsHandover() { 280 return mIsHandover; 281 } 282 getBringUpStateTime()283 public Date getBringUpStateTime() { 284 return mBringUpStateTime; 285 } 286 getUpStateTime()287 public Date getUpStateTime() { 288 return mUpStateTime; 289 } 290 291 @Override toString()292 public String toString() { 293 StringBuilder sb = new StringBuilder(); 294 String tunnelState = "UNKNOWN"; 295 switch (mState) { 296 case TUNNEL_DOWN: 297 tunnelState = "DOWN"; 298 break; 299 case TUNNEL_IN_BRINGUP: 300 tunnelState = "IN BRINGUP"; 301 break; 302 case TUNNEL_UP: 303 tunnelState = "UP"; 304 break; 305 case TUNNEL_IN_BRINGDOWN: 306 tunnelState = "IN BRINGDOWN"; 307 break; 308 case TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP: 309 tunnelState = "IN FORCE CLEAN WAS IN BRINGUP"; 310 break; 311 } 312 sb.append("\tCurrent State of this tunnel: " + mState + " " + tunnelState); 313 sb.append("\n\tTunnel state is in Handover: " + mIsHandover); 314 if (mBringUpStateTime != null) { 315 sb.append("\n\tTunnel bring up initiated at: " + mBringUpStateTime); 316 } else { 317 sb.append("\n\tPotential leak. Null mBringUpStateTime"); 318 } 319 if (mUpStateTime != null) { 320 sb.append("\n\tTunnel is up at: " + mUpStateTime); 321 } 322 if (mUpStateTime != null && mBringUpStateTime != null) { 323 long tunnelUpTime = mUpStateTime.getTime() - mBringUpStateTime.getTime(); 324 sb.append("\n\tTime taken for the tunnel to come up in ms: " + tunnelUpTime); 325 } 326 return sb.toString(); 327 } 328 } 329 330 @VisibleForTesting 331 class IwlanTunnelCallback implements EpdgTunnelManager.TunnelCallback { 332 333 DataServiceProvider mDataServiceProvider; 334 IwlanTunnelCallback(DataServiceProvider dsp)335 public IwlanTunnelCallback(DataServiceProvider dsp) { 336 mDataServiceProvider = dsp; 337 } 338 339 // TODO: full implementation 340 onOpened(String apnName, TunnelLinkProperties linkProperties)341 public void onOpened(String apnName, TunnelLinkProperties linkProperties) { 342 Log.d( 343 SUB_TAG, 344 "Tunnel opened!. APN: " + apnName + "linkproperties: " + linkProperties); 345 synchronized (mTunnelStateForApn) { 346 TunnelState tunnelState = mTunnelStateForApn.get(apnName); 347 // tunnelstate should not be null, design violation. 348 // if its null, we should crash and debug. 349 tunnelState.setTunnelLinkProperties(linkProperties); 350 tunnelState.setState(TunnelState.TUNNEL_UP); 351 mTunnelStats.reportTunnelSetupSuccess(apnName, tunnelState); 352 353 deliverCallback( 354 CALLBACK_TYPE_SETUP_DATACALL_COMPLETE, 355 DataServiceCallback.RESULT_SUCCESS, 356 tunnelState.getDataServiceCallback(), 357 apnTunnelStateToDataCallResponse(apnName)); 358 } 359 } 360 onClosed(String apnName, IwlanError error)361 public void onClosed(String apnName, IwlanError error) { 362 Log.d(SUB_TAG, "Tunnel closed!. APN: " + apnName + " Error: " + error); 363 // this is called, when a tunnel that is up, is closed. 364 // the expectation is error==NO_ERROR for user initiated/normal close. 365 synchronized (mTunnelStateForApn) { 366 TunnelState tunnelState = mTunnelStateForApn.get(apnName); 367 mTunnelStats.reportTunnelDown(apnName, tunnelState); 368 mTunnelStateForApn.remove(apnName); 369 370 if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP 371 || tunnelState.getState() 372 == TunnelState.TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP) { 373 DataCallResponse.Builder respBuilder = new DataCallResponse.Builder(); 374 respBuilder 375 .setId(apnName.hashCode()) 376 .setProtocolType(tunnelState.getProtocolType()); 377 378 if (tunnelState.getIsHandover()) { 379 respBuilder.setHandoverFailureMode( 380 DataCallResponse 381 .HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER); 382 } else { 383 respBuilder.setHandoverFailureMode( 384 DataCallResponse 385 .HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL); 386 } 387 388 if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP) { 389 respBuilder.setCause( 390 ErrorPolicyManager.getInstance(mContext, getSlotIndex()) 391 .getDataFailCause(apnName)); 392 respBuilder.setRetryDurationMillis( 393 ErrorPolicyManager.getInstance(mContext, getSlotIndex()) 394 .getCurrentRetryTimeMs(apnName)); 395 } else if (tunnelState.getState() 396 == TunnelState.TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP) { 397 respBuilder.setCause(DataFailCause.IWLAN_NETWORK_FAILURE); 398 respBuilder.setRetryDurationMillis(5000); 399 } 400 401 deliverCallback( 402 CALLBACK_TYPE_SETUP_DATACALL_COMPLETE, 403 DataServiceCallback.RESULT_SUCCESS, 404 tunnelState.getDataServiceCallback(), 405 respBuilder.build()); 406 return; 407 } 408 409 // iwlan service triggered teardown 410 if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGDOWN) { 411 412 // IO exception happens when IKE library fails to retransmit requests. 413 // This can happen for multiple reasons: 414 // 1. Network disconnection due to wifi off. 415 // 2. Epdg server does not respond. 416 // 3. Socket send/receive fails. 417 // Ignore this during tunnel bring down. 418 if (error.getErrorType() != IwlanError.NO_ERROR 419 && error.getErrorType() != IwlanError.IKE_INTERNAL_IO_EXCEPTION) { 420 Log.e(SUB_TAG, "Unexpected error during tunnel bring down: " + error); 421 } 422 423 deliverCallback( 424 CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE, 425 DataServiceCallback.RESULT_SUCCESS, 426 tunnelState.getDataServiceCallback(), 427 null); 428 429 return; 430 } 431 432 // just update list of data calls. No way to send error up 433 notifyDataCallListChanged(getCallList()); 434 } 435 } 436 } 437 438 private final class DSPHandler extends Handler { 439 private final String TAG = 440 IwlanDataService.class.getSimpleName() 441 + DSPHandler.class.getSimpleName() 442 + getSlotIndex(); 443 444 @Override handleMessage(Message msg)445 public void handleMessage(Message msg) { 446 Log.d(TAG, "msg.what = " + msg.what); 447 switch (msg.what) { 448 case IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT: 449 Log.d(TAG, "On CARRIER_CONFIG_CHANGED_EVENT"); 450 mCarrierConfigReady = true; 451 dnsPrefetchCheck(); 452 break; 453 case IwlanEventListener.CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT: 454 Log.d(TAG, "On CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT"); 455 mCarrierConfigReady = false; 456 break; 457 case IwlanEventListener.WIFI_CALLING_ENABLE_EVENT: 458 Log.d(TAG, "On WIFI_CALLING_ENABLE_EVENT"); 459 mWfcEnabled = true; 460 dnsPrefetchCheck(); 461 break; 462 case IwlanEventListener.WIFI_CALLING_DISABLE_EVENT: 463 Log.d(TAG, "On WIFI_CALLING_DISABLE_EVENT"); 464 mWfcEnabled = false; 465 break; 466 default: 467 Log.d(TAG, "Unknown message received!"); 468 break; 469 } 470 } 471 DSPHandler(Looper looper)472 DSPHandler(Looper looper) { 473 super(looper); 474 } 475 } 476 477 /** Holds all tunnel related time and count statistics for this IwlanDataServiceProvider */ 478 @VisibleForTesting 479 class IwlanDataTunnelStats { 480 481 // represents the start time from when the following events are recorded 482 private Date mStartTime; 483 484 // Stats for TunnelSetup Success time (BRING_UP -> UP state) 485 @VisibleForTesting 486 Map<String, LongSummaryStatistics> mTunnelSetupSuccessStats = 487 new HashMap<String, LongSummaryStatistics>(); 488 // Count for Tunnel Setup failures onClosed when in BRING_UP 489 @VisibleForTesting 490 Map<String, Long> mTunnelSetupFailureCounts = new HashMap<String, Long>(); 491 492 // Count for unsol tunnel down onClosed when in UP without deactivate 493 @VisibleForTesting 494 Map<String, Long> mUnsolTunnelDownCounts = new HashMap<String, Long>(); 495 496 // Stats for how long the tunnel is in up state onClosed when in UP 497 @VisibleForTesting 498 Map<String, LongSummaryStatistics> mTunnelUpStats = 499 new HashMap<String, LongSummaryStatistics>(); 500 501 private long statCount; 502 private final long COUNT_MAX = 1000; 503 private final int APN_COUNT_MAX = 10; 504 IwlanDataTunnelStats()505 public IwlanDataTunnelStats() { 506 mStartTime = Calendar.getInstance().getTime(); 507 statCount = 0L; 508 } 509 reportTunnelSetupSuccess(String apn, TunnelState tunnelState)510 public void reportTunnelSetupSuccess(String apn, TunnelState tunnelState) { 511 if (statCount > COUNT_MAX || maxApnReached()) { 512 reset(); 513 } 514 statCount++; 515 516 Date bringUpTime = tunnelState.getBringUpStateTime(); 517 Date upTime = tunnelState.getUpStateTime(); 518 519 if (bringUpTime != null && upTime != null) { 520 long tunnelUpTime = upTime.getTime() - bringUpTime.getTime(); 521 if (!mTunnelSetupSuccessStats.containsKey(apn)) { 522 mTunnelSetupSuccessStats.put(apn, new LongSummaryStatistics()); 523 } 524 LongSummaryStatistics stats = mTunnelSetupSuccessStats.get(apn); 525 stats.accept(tunnelUpTime); 526 mTunnelSetupSuccessStats.put(apn, stats); 527 } 528 } 529 reportTunnelDown(String apn, TunnelState tunnelState)530 public void reportTunnelDown(String apn, TunnelState tunnelState) { 531 if (statCount > COUNT_MAX || maxApnReached()) { 532 reset(); 533 } 534 statCount++; 535 536 // Setup fail 537 if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP) { 538 if (!mTunnelSetupFailureCounts.containsKey(apn)) { 539 mTunnelSetupFailureCounts.put(apn, 0L); 540 } 541 long count = mTunnelSetupFailureCounts.get(apn); 542 mTunnelSetupFailureCounts.put(apn, ++count); 543 return; 544 } 545 546 // Unsolicited tunnel down as tunnel has to be in BRINGDOWN if 547 // there is a deactivate call associated with this. 548 if (tunnelState.getState() == TunnelState.TUNNEL_UP) { 549 if (!mUnsolTunnelDownCounts.containsKey(apn)) { 550 mUnsolTunnelDownCounts.put(apn, 0L); 551 } 552 long count = mUnsolTunnelDownCounts.get(apn); 553 mUnsolTunnelDownCounts.put(apn, ++count); 554 } 555 Date currentTime = Calendar.getInstance().getTime(); 556 Date upTime = tunnelState.getUpStateTime(); 557 if (upTime != null) { 558 if (!mTunnelUpStats.containsKey(apn)) { 559 mTunnelUpStats.put(apn, new LongSummaryStatistics()); 560 } 561 LongSummaryStatistics stats = mTunnelUpStats.get(apn); 562 stats.accept(currentTime.getTime() - upTime.getTime()); 563 mTunnelUpStats.put(apn, stats); 564 } 565 } 566 maxApnReached()567 boolean maxApnReached() { 568 if (mTunnelSetupSuccessStats.size() >= APN_COUNT_MAX 569 || mTunnelSetupFailureCounts.size() >= APN_COUNT_MAX 570 || mUnsolTunnelDownCounts.size() >= APN_COUNT_MAX 571 || mTunnelUpStats.size() >= APN_COUNT_MAX) { 572 return true; 573 } 574 return false; 575 } 576 577 @Override toString()578 public String toString() { 579 StringBuilder sb = new StringBuilder(); 580 sb.append("IwlanDataTunnelStats:"); 581 sb.append("\n\tmStartTime: " + mStartTime); 582 sb.append("\n\ttunnelSetupSuccessStats:"); 583 for (Map.Entry<String, LongSummaryStatistics> entry : 584 mTunnelSetupSuccessStats.entrySet()) { 585 sb.append("\n\t Apn: " + entry.getKey()); 586 sb.append("\n\t " + entry.getValue()); 587 } 588 sb.append("\n\ttunnelUpStats:"); 589 for (Map.Entry<String, LongSummaryStatistics> entry : mTunnelUpStats.entrySet()) { 590 sb.append("\n\t Apn: " + entry.getKey()); 591 sb.append("\n\t " + entry.getValue()); 592 } 593 594 sb.append("\n\ttunnelSetupFailureCounts: "); 595 for (Map.Entry<String, Long> entry : mTunnelSetupFailureCounts.entrySet()) { 596 sb.append("\n\t Apn: " + entry.getKey()); 597 sb.append("\n\t counts: " + entry.getValue()); 598 } 599 sb.append("\n\tunsolTunnelDownCounts: "); 600 for (Map.Entry<String, Long> entry : mTunnelSetupFailureCounts.entrySet()) { 601 sb.append("\n\t Apn: " + entry.getKey()); 602 sb.append("\n\t counts: " + entry.getValue()); 603 } 604 sb.append("\n\tendTime: " + Calendar.getInstance().getTime()); 605 return sb.toString(); 606 } 607 reset()608 private void reset() { 609 mStartTime = Calendar.getInstance().getTime(); 610 mTunnelSetupSuccessStats = new HashMap<String, LongSummaryStatistics>(); 611 mTunnelUpStats = new HashMap<String, LongSummaryStatistics>(); 612 mTunnelSetupFailureCounts = new HashMap<String, Long>(); 613 mUnsolTunnelDownCounts = new HashMap<String, Long>(); 614 statCount = 0L; 615 } 616 } 617 getLooper()618 Looper getLooper() { 619 mHandlerThread = new HandlerThread("DSPHandlerThread"); 620 mHandlerThread.start(); 621 return mHandlerThread.getLooper(); 622 } 623 624 /** 625 * Constructor 626 * 627 * @param slotIndex SIM slot index the data service provider associated with. 628 */ IwlanDataServiceProvider(int slotIndex, IwlanDataService iwlanDataService)629 public IwlanDataServiceProvider(int slotIndex, IwlanDataService iwlanDataService) { 630 super(slotIndex); 631 SUB_TAG = TAG + "[" + slotIndex + "]"; 632 633 // TODO: 634 // get reference carrier config for this sub 635 // get reference to resolver 636 mIwlanDataService = iwlanDataService; 637 mIwlanTunnelCallback = new IwlanTunnelCallback(this); 638 mEpdgSelector = EpdgSelector.getSelectorInstance(mContext, slotIndex); 639 mTunnelStats = new IwlanDataTunnelStats(); 640 641 // Register IwlanEventListener 642 initHandler(); 643 List<Integer> events = new ArrayList<Integer>(); 644 events.add(IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT); 645 events.add(IwlanEventListener.CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT); 646 events.add(IwlanEventListener.WIFI_CALLING_ENABLE_EVENT); 647 events.add(IwlanEventListener.WIFI_CALLING_DISABLE_EVENT); 648 IwlanEventListener.getInstance(mContext, slotIndex).addEventListener(events, mHandler); 649 } 650 initHandler()651 void initHandler() { 652 mHandler = new DSPHandler(getLooper()); 653 } 654 655 @VisibleForTesting getTunnelManager()656 EpdgTunnelManager getTunnelManager() { 657 return EpdgTunnelManager.getInstance(mContext, getSlotIndex()); 658 } 659 660 // creates a DataCallResponse for an apn irrespective of state apnTunnelStateToDataCallResponse(String apn)661 private DataCallResponse apnTunnelStateToDataCallResponse(String apn) { 662 TunnelState tunnelState = mTunnelStateForApn.get(apn); 663 if (tunnelState == null) { 664 return null; 665 } 666 667 DataCallResponse.Builder responseBuilder = new DataCallResponse.Builder(); 668 responseBuilder 669 .setId(apn.hashCode()) 670 .setProtocolType(tunnelState.getProtocolType()) 671 .setCause(DataFailCause.NONE); 672 673 if (tunnelState.getState() != TunnelState.TUNNEL_UP) { 674 // no need to fill additional params 675 return responseBuilder.setLinkStatus(DataCallResponse.LINK_STATUS_UNKNOWN).build(); 676 } 677 678 // fill wildcard address for gatewayList (used by DataConnection to add routes) 679 List<InetAddress> gatewayList = new ArrayList<>(); 680 List<LinkAddress> linkAddrList = 681 tunnelState.getTunnelLinkProperties().internalAddresses(); 682 if (linkAddrList.stream().anyMatch(t -> t.isIpv4())) { 683 try { 684 gatewayList.add(Inet4Address.getByName("0.0.0.0")); 685 } catch (UnknownHostException e) { 686 // should never happen for static string 0.0.0.0 687 } 688 } 689 if (linkAddrList.stream().anyMatch(t -> t.isIpv6())) { 690 try { 691 gatewayList.add(Inet6Address.getByName("::")); 692 } catch (UnknownHostException e) { 693 // should never happen for static string :: 694 } 695 } 696 697 if (tunnelState.getTunnelLinkProperties().sliceInfo().isPresent()) { 698 responseBuilder.setSliceInfo( 699 tunnelState.getTunnelLinkProperties().sliceInfo().get()); 700 } 701 702 return responseBuilder 703 .setAddresses(linkAddrList) 704 .setDnsAddresses(tunnelState.getTunnelLinkProperties().dnsAddresses()) 705 .setPcscfAddresses(tunnelState.getTunnelLinkProperties().pcscfAddresses()) 706 .setInterfaceName(tunnelState.getTunnelLinkProperties().ifaceName()) 707 .setGatewayAddresses(gatewayList) 708 .setLinkStatus(DataCallResponse.LINK_STATUS_ACTIVE) 709 .setMtu(tunnelState.getLinkMtu()) 710 .setMtuV4(tunnelState.getLinkMtu()) 711 .setMtuV6(tunnelState.getLinkMtu()) 712 .setPduSessionId(tunnelState.getPduSessionId()) 713 .build(); // underlying n/w is same 714 } 715 getCallList()716 private List<DataCallResponse> getCallList() { 717 List<DataCallResponse> dcList = new ArrayList<>(); 718 for (String key : mTunnelStateForApn.keySet()) { 719 DataCallResponse dcRsp = apnTunnelStateToDataCallResponse(key); 720 if (dcRsp != null) { 721 Log.d(SUB_TAG, "Apn: " + key + "Link state: " + dcRsp.getLinkStatus()); 722 dcList.add(dcRsp); 723 } 724 } 725 return dcList; 726 } 727 deliverCallback( int callbackType, int result, DataServiceCallback callback, DataCallResponse rsp)728 private void deliverCallback( 729 int callbackType, int result, DataServiceCallback callback, DataCallResponse rsp) { 730 if (callback == null) { 731 Log.d(SUB_TAG, "deliverCallback: callback is null. callbackType:" + callbackType); 732 return; 733 } 734 Log.d( 735 SUB_TAG, 736 "Delivering callbackType:" 737 + callbackType 738 + " result:" 739 + result 740 + " rsp:" 741 + rsp); 742 switch (callbackType) { 743 case CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE: 744 callback.onDeactivateDataCallComplete(result); 745 // always update current datacalllist 746 notifyDataCallListChanged(getCallList()); 747 break; 748 749 case CALLBACK_TYPE_SETUP_DATACALL_COMPLETE: 750 if (result == DataServiceCallback.RESULT_SUCCESS && rsp == null) { 751 Log.d(SUB_TAG, "Warning: null rsp for success case"); 752 } 753 callback.onSetupDataCallComplete(result, rsp); 754 // always update current datacalllist 755 notifyDataCallListChanged(getCallList()); 756 break; 757 758 case CALLBACK_TYPE_GET_DATACALL_LIST_COMPLETE: 759 callback.onRequestDataCallListComplete(result, getCallList()); 760 // TODO: add code for the rest of the cases 761 } 762 } 763 764 /** 765 * Setup a data connection. 766 * 767 * @param accessNetworkType Access network type that the data call will be established on. 768 * Must be one of {@link android.telephony.AccessNetworkConstants.AccessNetworkType}. 769 * @param dataProfile Data profile used for data call setup. See {@link DataProfile} 770 * @param isRoaming True if the device is data roaming. 771 * @param allowRoaming True if data roaming is allowed by the user. 772 * @param reason The reason for data setup. Must be {@link #REQUEST_REASON_NORMAL} or {@link 773 * #REQUEST_REASON_HANDOVER}. 774 * @param linkProperties If {@code reason} is {@link #REQUEST_REASON_HANDOVER}, this is the 775 * link properties of the existing data connection, otherwise null. 776 * @param pduSessionId The pdu session id to be used for this data call. The standard range 777 * of values are 1-15 while 0 means no pdu session id was attached to this call. 778 * Reference: 3GPP TS 24.007 section 11.2.3.1b. 779 * @param sliceInfo The slice info related to this data call. 780 * @param trafficDescriptor TrafficDescriptor for which data connection needs to be 781 * established. It is used for URSP traffic matching as described in 3GPP TS 24.526 782 * Section 4.2.2. It includes an optional DNN which, if present, must be used for 783 * traffic matching; it does not specify the end point to be used for the data call. 784 * @param matchAllRuleAllowed Indicates if using default match-all URSP rule for this 785 * request is allowed. If false, this request must not use the match-all URSP rule and 786 * if a non-match-all rule is not found (or if URSP rules are not available) then {@link 787 * DataCallResponse#getCause()} is {@link 788 * android.telephony.DataFailCause#MATCH_ALL_RULE_NOT_ALLOWED}. This is needed as some 789 * requests need to have a hard failure if the intention cannot be met, for example, a 790 * zero-rating slice. 791 * @param callback The result callback for this request. 792 */ 793 @Override setupDataCall( int accessNetworkType, @NonNull DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, @Nullable LinkProperties linkProperties, @IntRange(from = 0, to = 15) int pduSessionId, @Nullable NetworkSliceInfo sliceInfo, @Nullable TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, @NonNull DataServiceCallback callback)794 public void setupDataCall( 795 int accessNetworkType, 796 @NonNull DataProfile dataProfile, 797 boolean isRoaming, 798 boolean allowRoaming, 799 int reason, 800 @Nullable LinkProperties linkProperties, 801 @IntRange(from = 0, to = 15) int pduSessionId, 802 @Nullable NetworkSliceInfo sliceInfo, 803 @Nullable TrafficDescriptor trafficDescriptor, 804 boolean matchAllRuleAllowed, 805 @NonNull DataServiceCallback callback) { 806 807 Log.d( 808 SUB_TAG, 809 "Setup data call with network: " 810 + accessNetworkType 811 + ", DataProfile: " 812 + dataProfile 813 + ", isRoaming:" 814 + isRoaming 815 + ", allowRoaming: " 816 + allowRoaming 817 + ", reason: " 818 + reason 819 + ", linkProperties: " 820 + linkProperties 821 + ", pduSessionId: " 822 + pduSessionId); 823 824 // Framework will never call bringup on the same APN back 2 back. 825 // but add a safety check 826 if ((accessNetworkType != AccessNetworkType.IWLAN) 827 || (dataProfile == null) 828 || (linkProperties == null && reason == DataService.REQUEST_REASON_HANDOVER)) { 829 830 deliverCallback( 831 CALLBACK_TYPE_SETUP_DATACALL_COMPLETE, 832 DataServiceCallback.RESULT_ERROR_INVALID_ARG, 833 callback, 834 null); 835 return; 836 } 837 838 synchronized (mTunnelStateForApn) { 839 boolean isDDS = IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()); 840 boolean isCSTEnabled = 841 IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex()); 842 boolean networkConnected = isNetworkConnected(isDDS, isCSTEnabled); 843 Log.d( 844 SUB_TAG, 845 "isDds: " 846 + isDDS 847 + ", isCstEnabled: " 848 + isCSTEnabled 849 + ", transport: " 850 + sDefaultDataTransport); 851 852 if (networkConnected == false 853 || mTunnelStateForApn.get(dataProfile.getApn()) != null) { 854 deliverCallback( 855 CALLBACK_TYPE_SETUP_DATACALL_COMPLETE, 856 5 /* DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */, 857 callback, 858 null); 859 return; 860 } 861 862 TunnelSetupRequest.Builder tunnelReqBuilder = 863 TunnelSetupRequest.builder() 864 .setApnName(dataProfile.getApn()) 865 .setNetwork(sNetwork) 866 .setIsRoaming(isRoaming) 867 .setPduSessionId(pduSessionId) 868 .setApnIpProtocol( 869 isRoaming 870 ? dataProfile.getRoamingProtocolType() 871 : dataProfile.getProtocolType()); 872 873 if (reason == DataService.REQUEST_REASON_HANDOVER) { 874 // for now assume that, at max, only one address of eachtype (v4/v6). 875 // TODO: Check if multiple ips can be sent in ike tunnel setup 876 for (LinkAddress lAddr : linkProperties.getLinkAddresses()) { 877 if (lAddr.isIpv4()) { 878 tunnelReqBuilder.setSrcIpv4Address(lAddr.getAddress()); 879 } else if (lAddr.isIpv6()) { 880 tunnelReqBuilder.setSrcIpv6Address(lAddr.getAddress()); 881 tunnelReqBuilder.setSrcIpv6AddressPrefixLength(lAddr.getPrefixLength()); 882 } 883 } 884 } 885 886 int apnTypeBitmask = dataProfile.getSupportedApnTypesBitmask(); 887 boolean isIMS = (apnTypeBitmask & ApnSetting.TYPE_IMS) == ApnSetting.TYPE_IMS; 888 boolean isEmergency = 889 (apnTypeBitmask & ApnSetting.TYPE_EMERGENCY) == ApnSetting.TYPE_EMERGENCY; 890 tunnelReqBuilder.setRequestPcscf(isIMS || isEmergency); 891 tunnelReqBuilder.setIsEmergency(isEmergency); 892 893 setTunnelState( 894 dataProfile, 895 callback, 896 TunnelState.TUNNEL_IN_BRINGUP, 897 null, 898 (reason == DataService.REQUEST_REASON_HANDOVER), 899 pduSessionId); 900 901 boolean result = 902 getTunnelManager() 903 .bringUpTunnel(tunnelReqBuilder.build(), getIwlanTunnelCallback()); 904 Log.d(SUB_TAG, "bringup Tunnel with result:" + result); 905 if (!result) { 906 deliverCallback( 907 CALLBACK_TYPE_SETUP_DATACALL_COMPLETE, 908 DataServiceCallback.RESULT_ERROR_INVALID_ARG, 909 callback, 910 null); 911 return; 912 } 913 } 914 } 915 916 /** 917 * Deactivate a data connection. The data service provider must implement this method to 918 * support data connection tear down. When completed or error, the service must invoke the 919 * provided callback to notify the platform. 920 * 921 * @param cid Call id returned in the callback of {@link 922 * DataServiceProvider#setupDataCall(int, DataProfile, boolean, boolean, int, 923 * LinkProperties, DataServiceCallback)}. 924 * @param reason The reason for data deactivation. Must be {@link #REQUEST_REASON_NORMAL}, 925 * {@link #REQUEST_REASON_SHUTDOWN} or {@link #REQUEST_REASON_HANDOVER}. 926 * @param callback The result callback for this request. Null if the client does not care 927 */ 928 @Override deactivateDataCall(int cid, int reason, DataServiceCallback callback)929 public void deactivateDataCall(int cid, int reason, DataServiceCallback callback) { 930 Log.d( 931 SUB_TAG, 932 "Deactivate data call " 933 + " reason: " 934 + reason 935 + " cid: " 936 + cid 937 + "callback: " 938 + callback); 939 940 synchronized (mTunnelStateForApn) { 941 for (String apnName : mTunnelStateForApn.keySet()) { 942 if (apnName.hashCode() == cid) { 943 /* 944 No need to check state since dataconnection in framework serializes 945 setup and deactivate calls using callId/cid. 946 */ 947 mTunnelStateForApn.get(apnName).setState(TunnelState.TUNNEL_IN_BRINGDOWN); 948 mTunnelStateForApn.get(apnName).setDataServiceCallback(callback); 949 boolean isConnected = 950 isNetworkConnected( 951 IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()), 952 IwlanHelper.isCrossSimCallingEnabled( 953 mContext, getSlotIndex())); 954 getTunnelManager().closeTunnel(apnName, !isConnected); 955 return; 956 } 957 } 958 959 deliverCallback( 960 CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE, 961 DataServiceCallback.RESULT_ERROR_INVALID_ARG, 962 callback, 963 null); 964 } 965 } 966 forceCloseTunnelsInDeactivatingState()967 public void forceCloseTunnelsInDeactivatingState() { 968 synchronized (mTunnelStateForApn) { 969 for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) { 970 TunnelState tunnelState = entry.getValue(); 971 if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGDOWN) { 972 getTunnelManager().closeTunnel(entry.getKey(), true); 973 } 974 } 975 } 976 } 977 forceCloseTunnels()978 void forceCloseTunnels() { 979 synchronized (mTunnelStateForApn) { 980 for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) { 981 getTunnelManager().closeTunnel(entry.getKey(), true); 982 } 983 } 984 } 985 986 /** 987 * Get the active data call list. 988 * 989 * @param callback The result callback for this request. 990 */ 991 @Override requestDataCallList(DataServiceCallback callback)992 public void requestDataCallList(DataServiceCallback callback) { 993 deliverCallback( 994 CALLBACK_TYPE_GET_DATACALL_LIST_COMPLETE, 995 DataServiceCallback.RESULT_SUCCESS, 996 callback, 997 null); 998 } 999 1000 @VisibleForTesting setTunnelState( DataProfile dataProfile, DataServiceCallback callback, int tunnelStatus, TunnelLinkProperties linkProperties, boolean isHandover, int pduSessionId)1001 void setTunnelState( 1002 DataProfile dataProfile, 1003 DataServiceCallback callback, 1004 int tunnelStatus, 1005 TunnelLinkProperties linkProperties, 1006 boolean isHandover, 1007 int pduSessionId) { 1008 TunnelState tunnelState = new TunnelState(callback); 1009 tunnelState.setState(tunnelStatus); 1010 tunnelState.setProtocolType(dataProfile.getProtocolType()); 1011 tunnelState.setTunnelLinkProperties(linkProperties); 1012 tunnelState.setIsHandover(isHandover); 1013 tunnelState.setPduSessionId(pduSessionId); 1014 mTunnelStateForApn.put(dataProfile.getApn(), tunnelState); 1015 } 1016 1017 @VisibleForTesting getIwlanTunnelCallback()1018 public IwlanTunnelCallback getIwlanTunnelCallback() { 1019 return mIwlanTunnelCallback; 1020 } 1021 1022 @VisibleForTesting getTunnelStats()1023 IwlanDataTunnelStats getTunnelStats() { 1024 return mTunnelStats; 1025 } 1026 updateNetwork(Network network)1027 private void updateNetwork(Network network) { 1028 if (network != null) { 1029 synchronized (mTunnelStateForApn) { 1030 for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) { 1031 TunnelState tunnelState = entry.getValue(); 1032 if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP) { 1033 // force close tunnels in bringup since IKE lib only supports 1034 // updating network for tunnels that are already up. 1035 // This may not result in actual closing of Ike Session since 1036 // epdg selection may not be complete yet. 1037 tunnelState.setState(TunnelState.TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP); 1038 getTunnelManager().closeTunnel(entry.getKey(), true); 1039 } else { 1040 if (mIwlanDataService.isNetworkConnected( 1041 IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()), 1042 IwlanHelper.isCrossSimCallingEnabled( 1043 mContext, getSlotIndex()))) { 1044 getTunnelManager().updateNetwork(network, entry.getKey()); 1045 } 1046 } 1047 } 1048 } 1049 } 1050 } 1051 dnsPrefetchCheck()1052 private void dnsPrefetchCheck() { 1053 boolean networkConnected = 1054 mIwlanDataService.isNetworkConnected( 1055 IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()), 1056 IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex())); 1057 /* Check if we need to do prefecting */ 1058 synchronized (mTunnelStateForApn) { 1059 if (networkConnected == true 1060 && mCarrierConfigReady == true 1061 && mWfcEnabled == true 1062 && mTunnelStateForApn.isEmpty()) { 1063 1064 // Get roaming status 1065 TelephonyManager telephonyManager = 1066 mContext.getSystemService(TelephonyManager.class); 1067 telephonyManager = 1068 telephonyManager.createForSubscriptionId( 1069 IwlanHelper.getSubId(mContext, getSlotIndex())); 1070 boolean isRoaming = telephonyManager.isNetworkRoaming(); 1071 Log.d(TAG, "Trigger EPDG prefetch. Roaming=" + isRoaming); 1072 1073 prefetchEpdgServerList(mIwlanDataService.sNetwork, isRoaming); 1074 } 1075 } 1076 } 1077 prefetchEpdgServerList(Network network, boolean isRoaming)1078 private void prefetchEpdgServerList(Network network, boolean isRoaming) { 1079 mEpdgSelector.getValidatedServerList( 1080 0, EpdgSelector.PROTO_FILTER_IPV4V6, isRoaming, false, network, null); 1081 mEpdgSelector.getValidatedServerList( 1082 0, EpdgSelector.PROTO_FILTER_IPV4V6, isRoaming, true, network, null); 1083 } 1084 1085 /** 1086 * Called when the instance of data service is destroyed (e.g. got unbind or binder died) or 1087 * when the data service provider is removed. 1088 */ 1089 @Override close()1090 public void close() { 1091 // TODO: call epdgtunnelmanager.releaseInstance or equivalent 1092 mIwlanDataService.removeDataServiceProvider(this); 1093 IwlanEventListener.getInstance(mContext, getSlotIndex()).removeEventListener(mHandler); 1094 mHandlerThread.quit(); 1095 } 1096 dump(FileDescriptor fd, PrintWriter pw, String[] args)1097 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1098 pw.println("---- IwlanDataServiceProvider[" + getSlotIndex() + "] ----"); 1099 boolean isDDS = IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()); 1100 boolean isCSTEnabled = IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex()); 1101 pw.println("isDefaultDataSub: " + isDDS + " isCrossSimEnabled: " + isCSTEnabled); 1102 pw.println( 1103 "isNetworkConnected: " 1104 + isNetworkConnected(isDDS, isCSTEnabled) 1105 + " Wfc enabled: " 1106 + mWfcEnabled); 1107 synchronized (mTunnelStateForApn) { 1108 for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) { 1109 pw.println("Tunnel state for APN: " + entry.getKey()); 1110 pw.println(entry.getValue()); 1111 } 1112 } 1113 pw.println(mTunnelStats); 1114 EpdgTunnelManager.getInstance(mContext, getSlotIndex()).dump(fd, pw, args); 1115 ErrorPolicyManager.getInstance(mContext, getSlotIndex()).dump(fd, pw, args); 1116 pw.println("-------------------------------------"); 1117 } 1118 } 1119 1120 @VisibleForTesting isNetworkConnected(boolean isDds, boolean isCstEnabled)1121 static synchronized boolean isNetworkConnected(boolean isDds, boolean isCstEnabled) { 1122 if (!isDds && isCstEnabled) { 1123 // Only Non-DDS sub with CST enabled, can use any transport. 1124 return sNetworkConnected; 1125 } else { 1126 // For all other cases, only wifi transport can be used. 1127 return ((sDefaultDataTransport == Transport.WIFI) && sNetworkConnected); 1128 } 1129 } 1130 1131 @VisibleForTesting 1132 /* Note: this api should have valid transport if networkConnected==true */ 1133 // Only synchronize on IwlanDataService.class for changes being made to static variables 1134 // Calls to DataServiceProvider object methods (or any objects in the future) should 1135 // not be made within synchronized block protected by IwlanDataService.class setNetworkConnected( boolean networkConnected, Network network, Transport transport)1136 static void setNetworkConnected( 1137 boolean networkConnected, Network network, Transport transport) { 1138 1139 boolean hasNetworkChanged = false; 1140 boolean hasTransportChanged = false; 1141 boolean hasNetworkConnectedChanged = false; 1142 1143 synchronized (IwlanDataService.class) { 1144 if (sNetworkConnected == networkConnected 1145 && network.equals(sNetwork) 1146 && sDefaultDataTransport == transport) { 1147 // Nothing changed 1148 return; 1149 } 1150 1151 // safety check 1152 if (networkConnected && transport == Transport.UNSPECIFIED_NETWORK) { 1153 Log.e(TAG, "setNetworkConnected: Network connected but transport unspecified"); 1154 return; 1155 } 1156 1157 if (!network.equals(sNetwork)) { 1158 Log.e(TAG, "setNetworkConnected NW changed from: " + sNetwork + " TO: " + network); 1159 hasNetworkChanged = true; 1160 } 1161 1162 if (transport != sDefaultDataTransport) { 1163 Log.d( 1164 TAG, 1165 "Transport was changed from " 1166 + sDefaultDataTransport.name() 1167 + " to " 1168 + transport.name()); 1169 hasTransportChanged = true; 1170 } 1171 1172 if (sNetworkConnected != networkConnected) { 1173 Log.d( 1174 TAG, 1175 "Network connected state change from " 1176 + sNetworkConnected 1177 + " to " 1178 + networkConnected); 1179 hasNetworkConnectedChanged = true; 1180 } 1181 1182 sNetworkConnected = networkConnected; 1183 sDefaultDataTransport = transport; 1184 sNetwork = network; 1185 if (!networkConnected) { 1186 // reset link protocol type 1187 sLinkProtocolType = LinkProtocolType.UNKNOWN; 1188 } 1189 } 1190 1191 if (networkConnected) { 1192 if (hasTransportChanged) { 1193 // Perform forceClose for tunnels in bringdown. 1194 // let framework handle explicit teardown 1195 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) { 1196 dp.forceCloseTunnelsInDeactivatingState(); 1197 } 1198 } 1199 1200 if (transport == Transport.WIFI && hasNetworkConnectedChanged) { 1201 IwlanEventListener.onWifiConnected(mContext); 1202 } 1203 // only prefetch dns and updateNetwork if Network has changed 1204 if (hasNetworkChanged) { 1205 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) { 1206 dp.dnsPrefetchCheck(); 1207 dp.updateNetwork(sNetwork); 1208 } 1209 } 1210 } else { 1211 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) { 1212 // once network is disconnected, even NAT KA offload fails 1213 // But we should still let framework do an explicit teardown 1214 // so as to not affect an ongoing handover 1215 // only force close tunnels in bring down state 1216 dp.forceCloseTunnelsInDeactivatingState(); 1217 } 1218 } 1219 } 1220 isLinkProtocolTypeChanged(LinkProperties linkProperties)1221 static boolean isLinkProtocolTypeChanged(LinkProperties linkProperties) { 1222 boolean hasIPV4 = false; 1223 boolean hasIPV6 = false; 1224 1225 LinkProtocolType linkProtocolType = null; 1226 if (linkProperties != null) { 1227 for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) { 1228 InetAddress inetaddr = linkAddress.getAddress(); 1229 // skip linklocal and loopback addresses 1230 if (!inetaddr.isLoopbackAddress() && !inetaddr.isLinkLocalAddress()) { 1231 if (inetaddr instanceof Inet4Address) { 1232 hasIPV4 = true; 1233 } else if (inetaddr instanceof Inet6Address) { 1234 hasIPV6 = true; 1235 } 1236 } 1237 } 1238 1239 if (hasIPV4 && hasIPV6) { 1240 linkProtocolType = LinkProtocolType.IPV4V6; 1241 } else if (hasIPV4) { 1242 linkProtocolType = LinkProtocolType.IPV4; 1243 } else if (hasIPV6) { 1244 linkProtocolType = LinkProtocolType.IPV6; 1245 } 1246 1247 if (sLinkProtocolType != linkProtocolType) { 1248 Log.d( 1249 TAG, 1250 "LinkProtocolType was changed from " 1251 + sLinkProtocolType 1252 + " to " 1253 + linkProtocolType); 1254 sLinkProtocolType = linkProtocolType; 1255 return true; 1256 } 1257 return false; 1258 } 1259 Log.w(TAG, "linkProperties is NULL."); 1260 return false; 1261 } 1262 1263 /** 1264 * Get the DataServiceProvider associated with the slotId 1265 * 1266 * @param slotId slot index 1267 * @return DataService.DataServiceProvider associated with the slot 1268 */ getDataServiceProvider(int slotId)1269 public static DataService.DataServiceProvider getDataServiceProvider(int slotId) { 1270 DataServiceProvider ret = null; 1271 if (!sIwlanDataServiceProviderList.isEmpty()) { 1272 for (IwlanDataServiceProvider provider : sIwlanDataServiceProviderList) { 1273 if (provider.getSlotIndex() == slotId) { 1274 ret = provider; 1275 break; 1276 } 1277 } 1278 } 1279 return ret; 1280 } 1281 getContext()1282 public static Context getContext() { 1283 return mContext; 1284 } 1285 1286 @Override onCreateDataServiceProvider(int slotIndex)1287 public DataServiceProvider onCreateDataServiceProvider(int slotIndex) { 1288 // TODO: validity check on slot index 1289 Log.d(TAG, "Creating provider for " + slotIndex); 1290 1291 if (mNetworkMonitorCallback == null) { 1292 // start monitoring network 1293 mNetworkCallbackHandlerThread = 1294 new HandlerThread(IwlanNetworkService.class.getSimpleName()); 1295 mNetworkCallbackHandlerThread.start(); 1296 Looper looper = mNetworkCallbackHandlerThread.getLooper(); 1297 Handler handler = new Handler(looper); 1298 1299 // register for default network callback 1300 ConnectivityManager connectivityManager = 1301 mContext.getSystemService(ConnectivityManager.class); 1302 mNetworkMonitorCallback = new IwlanNetworkMonitorCallback(); 1303 connectivityManager.registerDefaultNetworkCallback(mNetworkMonitorCallback, handler); 1304 Log.d(TAG, "Registered with Connectivity Service"); 1305 } 1306 1307 IwlanDataServiceProvider dp = new IwlanDataServiceProvider(slotIndex, this); 1308 addIwlanDataServiceProvider(dp); 1309 return dp; 1310 } 1311 removeDataServiceProvider(IwlanDataServiceProvider dp)1312 public void removeDataServiceProvider(IwlanDataServiceProvider dp) { 1313 sIwlanDataServiceProviderList.remove(dp); 1314 if (sIwlanDataServiceProviderList.isEmpty()) { 1315 // deinit network related stuff 1316 ConnectivityManager connectivityManager = 1317 mContext.getSystemService(ConnectivityManager.class); 1318 connectivityManager.unregisterNetworkCallback(mNetworkMonitorCallback); 1319 mNetworkCallbackHandlerThread.quit(); // no need to quitSafely 1320 mNetworkCallbackHandlerThread = null; 1321 mNetworkMonitorCallback = null; 1322 } 1323 } 1324 1325 @VisibleForTesting addIwlanDataServiceProvider(IwlanDataServiceProvider dp)1326 void addIwlanDataServiceProvider(IwlanDataServiceProvider dp) { 1327 sIwlanDataServiceProviderList.add(dp); 1328 } 1329 1330 @VisibleForTesting setAppContext(Context appContext)1331 void setAppContext(Context appContext) { 1332 mContext = appContext; 1333 } 1334 1335 @VisibleForTesting getNetworkMonitorCallback()1336 IwlanNetworkMonitorCallback getNetworkMonitorCallback() { 1337 return mNetworkMonitorCallback; 1338 } 1339 1340 @Override onCreate()1341 public void onCreate() { 1342 setAppContext(getApplicationContext()); 1343 IwlanBroadcastReceiver.startListening(mContext); 1344 } 1345 1346 @Override onDestroy()1347 public void onDestroy() { 1348 IwlanBroadcastReceiver.stopListening(mContext); 1349 } 1350 1351 @Override onBind(Intent intent)1352 public IBinder onBind(Intent intent) { 1353 Log.d(TAG, "Iwlanservice onBind"); 1354 return super.onBind(intent); 1355 } 1356 1357 @Override onUnbind(Intent intent)1358 public boolean onUnbind(Intent intent) { 1359 Log.d(TAG, "IwlanService onUnbind"); 1360 // force close all the tunnels when there are no clients 1361 // active 1362 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) { 1363 dp.forceCloseTunnels(); 1364 } 1365 return super.onUnbind(intent); 1366 } 1367 1368 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1369 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1370 String transport = "UNSPECIFIED"; 1371 if (sDefaultDataTransport == Transport.MOBILE) { 1372 transport = "CELLULAR"; 1373 } else if (sDefaultDataTransport == Transport.WIFI) { 1374 transport = "WIFI"; 1375 } 1376 pw.println("Default transport: " + transport); 1377 for (IwlanDataServiceProvider provider : sIwlanDataServiceProviderList) { 1378 pw.println(); 1379 provider.dump(fd, pw, args); 1380 pw.println(); 1381 pw.println(); 1382 } 1383 } 1384 } 1385