/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.iwlan; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.ipsec.ike.ike3gpp.Ike3gppParams.PDU_SESSION_ID_UNSET; import static android.telephony.TelephonyManager.CALL_STATE_IDLE; import static android.telephony.TelephonyManager.CALL_STATE_RINGING; import static android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_LTE; import static android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_NR; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_DEACTIVATE_DATA_CALL; import static com.google.android.iwlan.epdg.EpdgTunnelManager.BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; import android.net.ipsec.ike.exceptions.IkeInternalException; import android.net.vcn.VcnTransportInfo; import android.os.PersistableBundle; import android.os.test.TestLooper; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierConfigManager; import android.telephony.DataFailCause; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; import android.telephony.data.DataService; import android.telephony.data.DataServiceCallback; import android.telephony.data.IDataServiceCallback; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; import android.telephony.ims.ImsManager; import android.telephony.ims.ImsMmTelManager; import com.google.android.iwlan.IwlanDataService.IwlanDataServiceProvider; import com.google.android.iwlan.IwlanDataService.IwlanDataServiceProvider.IwlanTunnelCallback; import com.google.android.iwlan.IwlanDataService.IwlanDataServiceProvider.TunnelState; import com.google.android.iwlan.epdg.EpdgSelector; import com.google.android.iwlan.epdg.EpdgTunnelManager; import com.google.android.iwlan.epdg.NetworkSliceSelectionAssistanceInformation; import com.google.android.iwlan.epdg.TunnelLinkProperties; import com.google.android.iwlan.epdg.TunnelSetupRequest; import com.google.android.iwlan.flags.FeatureFlags; import com.google.android.iwlan.proto.MetricsAtom; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import java.lang.reflect.Method; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.LongSummaryStatistics; public class IwlanDataServiceTest { private static final int DEFAULT_SLOT_INDEX = 0; private static final int DEFAULT_SUB_INDEX = 0; private static final int INVALID_SUB_INDEX = -1; private static final int LINK_MTU = 1280; private static final String TEST_APN_NAME = "ims"; private static final String IP_ADDRESS = "192.0.2.1"; private static final String DNS_ADDRESS = "8.8.8.8"; private static final String GATEWAY_ADDRESS = "0.0.0.0"; private static final String PSCF_ADDRESS = "10.159.204.230"; private static final String INTERFACE_NAME = "ipsec6"; @Mock private Context mMockContext; @Mock private SubscriptionManager mMockSubscriptionManager; @Mock private SubscriptionInfo mMockSubscriptionInfo; @Mock private ContentResolver mMockContentResolver; @Mock private ConnectivityManager mMockConnectivityManager; @Mock private DataServiceCallback mMockDataServiceCallback; @Mock private EpdgTunnelManager mMockEpdgTunnelManager; @Mock private IwlanDataServiceProvider mMockIwlanDataServiceProvider; @Mock private Network mMockNetwork; @Mock private TunnelLinkProperties mMockTunnelLinkProperties; @Mock private ErrorPolicyManager mMockErrorPolicyManager; @Mock private ImsManager mMockImsManager; @Mock private ImsMmTelManager mMockImsMmTelManager; @Mock private TelephonyManager mMockTelephonyManager; @Mock private EpdgSelector mMockEpdgSelector; @Mock private LinkAddress mMockIPv4LinkAddress; @Mock private LinkAddress mMockIPv6LinkAddress; @Mock private Inet4Address mMockInet4Address; @Mock private Inet6Address mMockInet6Address; @Mock private CarrierConfigManager mMockCarrierConfigManager; @Mock private FeatureFlags mFakeFeatureFlags; MockitoSession mStaticMockSession; private LinkProperties mLinkProperties; private List mResultDataCallList; private @DataServiceCallback.ResultCode int mResultCode; private IwlanDataService mIwlanDataService; private IwlanDataServiceProvider mSpyIwlanDataServiceProvider; private TestLooper mTestLooper = new TestLooper(); private long mMockedCalendarTime; private ArgumentCaptor mNetworkCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class); private final class IwlanDataServiceCallback extends IDataServiceCallback.Stub { private final String mTag; IwlanDataServiceCallback(String tag) { mTag = tag; } @Override public void onSetupDataCallComplete( @DataServiceCallback.ResultCode int resultCode, DataCallResponse response) {} @Override public void onDeactivateDataCallComplete(@DataServiceCallback.ResultCode int resultCode) {} @Override public void onSetInitialAttachApnComplete(@DataServiceCallback.ResultCode int resultCode) {} @Override public void onSetDataProfileComplete(@DataServiceCallback.ResultCode int resultCode) {} @Override public void onRequestDataCallListComplete( @DataServiceCallback.ResultCode int resultCode, List dataCallList) { mResultCode = resultCode; mResultDataCallList = new ArrayList(dataCallList); } @Override public void onDataCallListChanged(List dataCallList) {} @Override public void onHandoverStarted(@DataServiceCallback.ResultCode int result) {} @Override public void onHandoverCancelled(@DataServiceCallback.ResultCode int result) {} @Override public void onApnUnthrottled(String apn) {} @Override public void onDataProfileUnthrottled(DataProfile dataProfile) {} } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mStaticMockSession = mockitoSession() .mockStatic(EpdgSelector.class) .mockStatic(EpdgTunnelManager.class) .mockStatic(ErrorPolicyManager.class) .mockStatic(IwlanBroadcastReceiver.class) .mockStatic(SubscriptionManager.class) .mockStatic(IwlanCarrierConfig.class) .strictness(Strictness.LENIENT) .startMocking(); when(mMockContext.getSystemService(eq(ConnectivityManager.class))) .thenReturn(mMockConnectivityManager); when(mMockContext.getSystemService(eq(SubscriptionManager.class))) .thenReturn(mMockSubscriptionManager); doNothing() .when(mMockConnectivityManager) .registerSystemDefaultNetworkCallback(mNetworkCallbackCaptor.capture(), any()); when(EpdgTunnelManager.getInstance(mMockContext, DEFAULT_SLOT_INDEX)) .thenReturn(mMockEpdgTunnelManager); when(mMockSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt())) .thenReturn(mMockSubscriptionInfo); when(mMockSubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX); when(mMockSubscriptionManager.getSlotIndex(DEFAULT_SUB_INDEX)) .thenReturn(DEFAULT_SLOT_INDEX); when(mMockSubscriptionManager.getSlotIndex(DEFAULT_SUB_INDEX + 1)) .thenReturn(DEFAULT_SLOT_INDEX + 1); when(mMockSubscriptionInfo.getSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX); when(mMockContext.getSystemService(eq(TelephonyManager.class))) .thenReturn(mMockTelephonyManager); when(mMockTelephonyManager.createForSubscriptionId(eq(DEFAULT_SUB_INDEX))) .thenReturn(mMockTelephonyManager); when(mMockTelephonyManager.isNetworkRoaming()).thenReturn(false); when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); when(mMockContext.getSystemService(eq(ImsManager.class))).thenReturn(mMockImsManager); when(mMockImsManager.getImsMmTelManager(anyInt())).thenReturn(mMockImsMmTelManager); when(mMockImsMmTelManager.isVoWiFiSettingEnabled()).thenReturn(false); when(EpdgSelector.getSelectorInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockEpdgSelector); when(mMockIPv4LinkAddress.getAddress()).thenReturn(mMockInet4Address); when(mMockIPv6LinkAddress.getAddress()).thenReturn(mMockInet6Address); mIwlanDataService = spy(new IwlanDataService(mFakeFeatureFlags)); when(mMockContext.getSystemService(eq(CarrierConfigManager.class))) .thenReturn(mMockCarrierConfigManager); // Injects the test looper into the IwlanDataServiceHandler doReturn(mTestLooper.getLooper()).when(mIwlanDataService).getLooper(); mIwlanDataService.setAppContext(mMockContext); mSpyIwlanDataServiceProvider = spy( (IwlanDataServiceProvider) mIwlanDataService.onCreateDataServiceProvider(DEFAULT_SLOT_INDEX)); mTestLooper.dispatchAll(); when(Calendar.getInstance().getTime()).thenAnswer(i -> mMockedCalendarTime); mLinkProperties = new LinkProperties(); mLinkProperties.setInterfaceName("wlan0"); mLinkProperties.addLinkAddress(mMockIPv4LinkAddress); when(mMockConnectivityManager.getLinkProperties(eq(mMockNetwork))) .thenReturn(mLinkProperties); when(mMockTunnelLinkProperties.ifaceName()).thenReturn("mockipsec0"); } private void moveTimeForwardAndDispatch(long milliSeconds) { mTestLooper.moveTimeForward(milliSeconds); mTestLooper.dispatchAll(); } @After public void cleanUp() throws Exception { mStaticMockSession.finishMocking(); mSpyIwlanDataServiceProvider.close(); mTestLooper.dispatchAll(); if (mIwlanDataService != null) { mIwlanDataService.onDestroy(); } } public Network createMockNetwork(LinkProperties linkProperties) { Network network = mock(Network.class); when(mMockConnectivityManager.getLinkProperties(eq(network))).thenReturn(linkProperties); return network; } private NetworkCallback getNetworkMonitorCallback() { return mNetworkCallbackCaptor.getValue(); } private void onSystemDefaultNetworkConnected( Network network, LinkProperties linkProperties, int transportType, int subId) { NetworkCapabilities nc = prepareNetworkCapabilitiesForTest( transportType, subId /* unused if transportType is TRANSPORT_WIFI */, false /* isVcn */); NetworkCallback networkMonitorCallback = getNetworkMonitorCallback(); networkMonitorCallback.onCapabilitiesChanged(network, nc); networkMonitorCallback.onLinkPropertiesChanged(network, linkProperties); mTestLooper.dispatchAll(); } private void onSystemDefaultNetworkConnected(int transportType) { Network newNetwork = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork, mLinkProperties, transportType, DEFAULT_SUB_INDEX); } private void onSystemDefaultNetworkLost() { NetworkCallback networkMonitorCallback = getNetworkMonitorCallback(); networkMonitorCallback.onLost(mMockNetwork); mTestLooper.dispatchAll(); } @Test public void testWifiOnConnected() { onSystemDefaultNetworkConnected(TRANSPORT_WIFI); assertTrue( mIwlanDataService.isNetworkConnected( false /* isActiveDataOnOtherSub */, false /* isCstEnabled */)); } @Test public void testWifiOnLost() { when(mMockIwlanDataServiceProvider.getSlotIndex()).thenReturn(DEFAULT_SLOT_INDEX + 1); mIwlanDataService.addIwlanDataServiceProvider(mMockIwlanDataServiceProvider); onSystemDefaultNetworkLost(); assertFalse( mIwlanDataService.isNetworkConnected( false /* isActiveDataOnOtherSub */, false /* isCstEnabled */)); verify(mMockIwlanDataServiceProvider).forceCloseTunnelsInDeactivatingState(); mIwlanDataService.removeDataServiceProvider(mMockIwlanDataServiceProvider); mTestLooper.dispatchAll(); } @Test public void testWifiOnReconnected() { Network newNetwork = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); verify(mMockEpdgTunnelManager, times(1)).updateNetwork(eq(newNetwork), eq(mLinkProperties)); onSystemDefaultNetworkLost(); onSystemDefaultNetworkConnected( newNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); verify(mMockEpdgTunnelManager, times(2)).updateNetwork(eq(newNetwork), eq(mLinkProperties)); } @Test public void testOnLinkPropertiesChangedForConnectedNetwork() { NetworkCallback networkCallback = getNetworkMonitorCallback(); onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); clearInvocations(mMockEpdgTunnelManager); LinkProperties newLinkProperties = new LinkProperties(mLinkProperties); newLinkProperties.setInterfaceName("wlan0"); newLinkProperties.addLinkAddress(mMockIPv6LinkAddress); networkCallback.onLinkPropertiesChanged(mMockNetwork, newLinkProperties); verify(mMockEpdgTunnelManager, times(1)) .updateNetwork(eq(mMockNetwork), eq(newLinkProperties)); } @Test public void testOnLinkPropertiesChangedForNonConnectedNetwork() { NetworkCallback networkCallback = getNetworkMonitorCallback(); onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); clearInvocations(mMockEpdgTunnelManager); LinkProperties newLinkProperties = new LinkProperties(); newLinkProperties.setInterfaceName("wlan0"); newLinkProperties.addLinkAddress(mMockIPv6LinkAddress); Network newNetwork = createMockNetwork(newLinkProperties); networkCallback.onLinkPropertiesChanged(newNetwork, newLinkProperties); verify(mMockEpdgTunnelManager, never()) .updateNetwork(eq(newNetwork), any(LinkProperties.class)); } @Test public void testOnLinkPropertiesChangedWithClatInstalled() throws Exception { NetworkCallback networkCallback = getNetworkMonitorCallback(); mLinkProperties.setLinkAddresses( new ArrayList<>(Collections.singletonList(mMockIPv6LinkAddress))); onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); clearInvocations(mMockEpdgTunnelManager); // LinkProperties#addStackedLink() is marked with @UnsupportedAppUsage LinkProperties newLinkProperties = new LinkProperties(mLinkProperties); newLinkProperties.setInterfaceName("wlan0"); LinkProperties stackedLink = new LinkProperties(); stackedLink.setInterfaceName("v4-wlan0"); stackedLink.addLinkAddress(mMockIPv4LinkAddress); Class[] parameterTypes = new Class[] {LinkProperties.class}; Object[] args = new Object[] {stackedLink}; callUnsupportedAppUsageMethod(newLinkProperties, "addStackedLink", parameterTypes, args); assertNotEquals(mLinkProperties, newLinkProperties); networkCallback.onLinkPropertiesChanged(mMockNetwork, newLinkProperties); verify(mMockEpdgTunnelManager, times(1)) .updateNetwork(eq(mMockNetwork), eq(newLinkProperties)); } @Test public void testOnLinkPropertiesChangedForBringingUpIkeSession() { DataProfile dp = buildImsDataProfile(); NetworkCallback networkCallback = getNetworkMonitorCallback(); onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); clearInvocations(mMockEpdgTunnelManager); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ false /* isHandover */, 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); LinkProperties newLinkProperties = new LinkProperties(mLinkProperties); newLinkProperties.setInterfaceName("wlan0"); newLinkProperties.addLinkAddress(mMockIPv6LinkAddress); networkCallback.onLinkPropertiesChanged(mMockNetwork, newLinkProperties); verify(mMockEpdgTunnelManager, times(1)) .updateNetwork(eq(mMockNetwork), eq(newLinkProperties)); verify(mMockEpdgTunnelManager, never()) .closeTunnel(any(), anyBoolean(), any(), any(), anyInt()); } @Test public void testNetworkNotConnectedWithCellularOnSameSubAndCrossSimEnabled() throws InterruptedException { NetworkCapabilities nc = prepareNetworkCapabilitiesForTest( TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX, false /* isVcn */); getNetworkMonitorCallback().onCapabilitiesChanged(mMockNetwork, nc); boolean isActiveDataOnOtherSub = mIwlanDataService.isActiveDataOnOtherSub(DEFAULT_SLOT_INDEX); assertFalse(isActiveDataOnOtherSub); assertFalse( mIwlanDataService.isNetworkConnected( isActiveDataOnOtherSub, true /* isCstEnabled */)); } @Test public void testCrossSimNetworkConnectedWithCellularOnDifferentSub() throws InterruptedException { NetworkCapabilities nc = prepareNetworkCapabilitiesForTest( TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX + 1, false /* isVcn */); getNetworkMonitorCallback().onCapabilitiesChanged(mMockNetwork, nc); boolean isActiveDataOnOtherSub = mIwlanDataService.isActiveDataOnOtherSub(DEFAULT_SLOT_INDEX); assertTrue(isActiveDataOnOtherSub); assertTrue( mIwlanDataService.isNetworkConnected( isActiveDataOnOtherSub, true /* isCstEnabled */)); } @Test public void testCrossSimNetworkConnectedWithVcnCellularOnDifferentSub() throws InterruptedException { NetworkCapabilities nc = prepareNetworkCapabilitiesForTest( TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX + 1, true /* isVcn */); getNetworkMonitorCallback().onCapabilitiesChanged(mMockNetwork, nc); boolean isActiveDataOnOtherSub = mIwlanDataService.isActiveDataOnOtherSub(DEFAULT_SLOT_INDEX); assertTrue(isActiveDataOnOtherSub); assertTrue( mIwlanDataService.isNetworkConnected( isActiveDataOnOtherSub, true /* isCstEnabled */)); } @Test public void testOnCrossSimCallingEnable_doNotUpdateTunnelManagerIfCellularDataOnSameSub() throws Exception { when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true); Network newNetwork = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork, mLinkProperties, TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX); mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT, DEFAULT_SLOT_INDEX, 0 /* unused */) .sendToTarget(); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, never()) .updateNetwork(eq(newNetwork), any(LinkProperties.class)); } @Test public void testOnCrossSimCallingEnable_updateTunnelManagerIfCellularDataOnDifferentSub() throws Exception { when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true); Network newNetwork = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork, mLinkProperties, TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX + 1); verify(mMockEpdgTunnelManager, times(1)).updateNetwork(eq(newNetwork), eq(mLinkProperties)); mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT, DEFAULT_SLOT_INDEX, 0 /* unused */) .sendToTarget(); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, times(2)).updateNetwork(eq(newNetwork), eq(mLinkProperties)); } @Test public void testOnCrossSimCallingEnable_doNotUpdateTunnelManagerIfNoNetwork() throws Exception { when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true); onSystemDefaultNetworkLost(); mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT, DEFAULT_SLOT_INDEX, 0 /* unused */) .sendToTarget(); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, never()) .updateNetwork(any(Network.class), any(LinkProperties.class)); } @Test public void testOnEthernetConnection_doNotUpdateTunnelManager() throws Exception { Network newNetwork = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork, mLinkProperties, TRANSPORT_ETHERNET, DEFAULT_SUB_INDEX); verify(mMockEpdgTunnelManager, never()) .updateNetwork(eq(newNetwork), any(LinkProperties.class)); } @Test public void testAddDuplicateDataServiceProviderThrows() throws Exception { when(mMockIwlanDataServiceProvider.getSlotIndex()).thenReturn(DEFAULT_SLOT_INDEX); assertThrows( IllegalStateException.class, () -> mIwlanDataService.addIwlanDataServiceProvider(mMockIwlanDataServiceProvider)); } @Test public void testRemoveDataServiceProvider() { when(mMockIwlanDataServiceProvider.getSlotIndex()).thenReturn(DEFAULT_SLOT_INDEX); mIwlanDataService.removeDataServiceProvider(mMockIwlanDataServiceProvider); mTestLooper.dispatchAll(); verify(mIwlanDataService, times(1)).deinitNetworkCallback(); mIwlanDataService.onCreateDataServiceProvider(DEFAULT_SLOT_INDEX); mTestLooper.dispatchAll(); } @Test public void testRequestDataCallListPass() throws Exception { DataProfile dp = buildImsDataProfile(); List mInternalAddressList; List mDNSAddressList; List mGatewayAddressList; List mPCSFAddressList; IwlanDataServiceCallback callback = new IwlanDataServiceCallback("requestDataCallList"); TunnelLinkProperties mLinkProperties = createTunnelLinkProperties(); mSpyIwlanDataServiceProvider.setTunnelState( dp, new DataServiceCallback(callback), TunnelState.TUNNEL_UP, mLinkProperties, false, /* isHandover */ 1, /* pduSessionId */ true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.requestDataCallList(new DataServiceCallback(callback)); mTestLooper.dispatchAll(); assertEquals(mResultCode, DataServiceCallback.RESULT_SUCCESS); assertEquals(mResultDataCallList.size(), 1); for (DataCallResponse dataCallInfo : mResultDataCallList) { assertEquals(dataCallInfo.getId(), TEST_APN_NAME.hashCode()); assertEquals(dataCallInfo.getLinkStatus(), DataCallResponse.LINK_STATUS_ACTIVE); assertEquals(dataCallInfo.getProtocolType(), ApnSetting.PROTOCOL_IP); assertEquals(dataCallInfo.getInterfaceName(), INTERFACE_NAME); mInternalAddressList = dataCallInfo.getAddresses(); assertEquals(mInternalAddressList.size(), 1); for (LinkAddress mLinkAddress : mInternalAddressList) { assertEquals(mLinkAddress, new LinkAddress(InetAddress.getByName(IP_ADDRESS), 3)); } mDNSAddressList = dataCallInfo.getDnsAddresses(); assertEquals(mDNSAddressList.size(), 1); for (InetAddress mInetAddress : mDNSAddressList) { assertEquals(mInetAddress, InetAddress.getByName(DNS_ADDRESS)); } mGatewayAddressList = dataCallInfo.getGatewayAddresses(); assertEquals(mGatewayAddressList.size(), 1); for (InetAddress mInetAddress : mGatewayAddressList) { assertEquals(mInetAddress, Inet4Address.getByName(GATEWAY_ADDRESS)); } mPCSFAddressList = dataCallInfo.getPcscfAddresses(); assertEquals(mPCSFAddressList.size(), 1); for (InetAddress mInetAddress : mPCSFAddressList) { assertEquals(mInetAddress, InetAddress.getByName(PSCF_ADDRESS)); } assertEquals(dataCallInfo.getMtuV4(), LINK_MTU); assertEquals(dataCallInfo.getMtuV6(), LINK_MTU); } } @Test public void testRequestDataCallListEmpty() throws Exception { IwlanDataServiceCallback callback = new IwlanDataServiceCallback("requestDataCallList"); mSpyIwlanDataServiceProvider.requestDataCallList(new DataServiceCallback(callback)); mTestLooper.dispatchAll(); assertEquals(mResultCode, DataServiceCallback.RESULT_SUCCESS); assertEquals(mResultDataCallList.size(), 0); } @Test public void testIwlanSetupDataCallWithInvalidArg() { mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.UNKNOWN, /* AccessNetworkType */ null, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 2, /* pdu session id */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, timeout(1000).times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_ERROR_INVALID_ARG), isNull()); } @Test public void testIwlanSetupDataCallWithIllegalState() { DataProfile dp = buildImsDataProfile(); /* Wifi is not connected */ onSystemDefaultNetworkLost(); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pdu session id */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, timeout(1000).times(1)) .onSetupDataCallComplete( eq(5 /*DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */), isNull()); } @Test public void testIwlanDeactivateDataCallWithInvalidArg() { mSpyIwlanDataServiceProvider.deactivateDataCall( 0, /* cid */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, timeout(1000).times(1)) .onDeactivateDataCallComplete(eq(DataServiceCallback.RESULT_ERROR_INVALID_ARG)); } @Test public void testIwlanSetupDataCallWithBringUpTunnel() { DataProfile dp = buildImsDataProfile(); /* Wifi is connected */ onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); /* Check bringUpTunnel() is called. */ verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel( any(TunnelSetupRequest.class), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class)); /* Check callback result is RESULT_SUCCESS when onOpened() is called. */ mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onOpened(TEST_APN_NAME, mMockTunnelLinkProperties); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), any(DataCallResponse.class)); } @Test public void testIwlanSetupDataCallWithBringUpTunnelAndNullApnSetting() { DataProfile dp = buildImsDataProfileWithEmptyApnSetting(); /* Wifi is connected */ onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_ERROR_INVALID_ARG), isNull()); } @Test public void testSliceInfoInclusionInDataCallResponse() throws Exception { DataProfile dp = buildImsDataProfile(); /* Wifi is connected */ onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); /* Check bringUpTunnel() is called. */ verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel( any(TunnelSetupRequest.class), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class)); /* Check callback result is RESULT_SUCCESS when onOpened() is called. */ TunnelLinkProperties tp = createTunnelLinkProperties(); ArgumentCaptor dataCallResponseCaptor = ArgumentCaptor.forClass(DataCallResponse.class); mSpyIwlanDataServiceProvider.getIwlanTunnelCallback().onOpened(TEST_APN_NAME, tp); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), dataCallResponseCaptor.capture()); /* check that sliceinfo is filled up and matches */ DataCallResponse dataCallResponse = dataCallResponseCaptor.getValue(); assertNotNull(dataCallResponse.getSliceInfo()); assertEquals(dataCallResponse.getSliceInfo(), tp.sliceInfo().get()); } @Test public void testIwlanDeactivateDataCallWithCloseTunnel() { DataProfile dp = buildImsDataProfile(); onSystemDefaultNetworkConnected(TRANSPORT_WIFI); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ false, /* isHandover */ 1, /* pduSessionId */ true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.deactivateDataCall( TEST_APN_NAME.hashCode() /* cid: hashcode() of "ims" */, DataService.REQUEST_REASON_NORMAL, mMockDataServiceCallback); mTestLooper.dispatchAll(); /* Check closeTunnel() is called. */ verify(mMockEpdgTunnelManager, times(1)) .closeTunnel( eq(TEST_APN_NAME), eq(false), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onDeactivateDataCallComplete(eq(DataServiceCallback.RESULT_SUCCESS)); } @Test public void testDeactivateDataCall_ImmediateReleaseAfterHandover() { DataProfile dp = buildImsDataProfile(); onSystemDefaultNetworkConnected(TRANSPORT_WIFI); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_UP, null, /* linkProperties */ false, /* isHandover */ 1, /* pduSessionId */ true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.deactivateDataCall( TEST_APN_NAME.hashCode() /* cid: hashcode() of "ims" */, DataService.REQUEST_REASON_HANDOVER, mMockDataServiceCallback); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(50); /* Check closeTunnel() is called. */ verify(mMockEpdgTunnelManager, times(1)) .closeTunnel( eq(TEST_APN_NAME), eq(true) /* forceClose */, any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onDeactivateDataCallComplete(eq(DataServiceCallback.RESULT_SUCCESS)); } @Test public void testDeactivateDataCall_DelayedReleaseAfterHandover() { DataProfile dp = buildImsDataProfile(); when(IwlanCarrierConfig.getConfigInt( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT)) .thenReturn(3); onSystemDefaultNetworkConnected(TRANSPORT_WIFI); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_UP, null, /* linkProperties */ false, /* isHandover */ 1, /* pduSessionId */ true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.deactivateDataCall( TEST_APN_NAME.hashCode() /* cid: hashcode() of "ims" */, DataService.REQUEST_REASON_HANDOVER, mMockDataServiceCallback); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(2950); /* Check closeTunnel() is called. */ verify(mMockEpdgTunnelManager, never()) .closeTunnel( eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); moveTimeForwardAndDispatch(50); /* Check closeTunnel() is called. */ verify(mMockEpdgTunnelManager, times(1)) .closeTunnel( eq(TEST_APN_NAME), eq(true) /* forceClose */, any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onDeactivateDataCallComplete(eq(DataServiceCallback.RESULT_SUCCESS)); } @Test public void testDeactivateDataCall_DelayedReleaseAfterHandover_NetworkReleaseBeforeDelay() { DataProfile dp = buildImsDataProfile(); when(IwlanCarrierConfig.getConfigInt( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_HANDOVER_TO_WWAN_RELEASE_DELAY_SECOND_INT)) .thenReturn(3); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.NONE); onSystemDefaultNetworkConnected(TRANSPORT_WIFI); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_UP, null, /* linkProperties */ false, /* isHandover */ 1, /* pduSessionId */ true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, /* type IMS */ true, 13, /* LTE */ false, true, 1 /* Transport WiFi */); mSpyIwlanDataServiceProvider.deactivateDataCall( TEST_APN_NAME.hashCode() /* cid: hashcode() of "ims" */, DataService.REQUEST_REASON_HANDOVER, mMockDataServiceCallback); mTestLooper.dispatchAll(); moveTimeForwardAndDispatch(50); /* Check closeTunnel() is called. */ verify(mMockEpdgTunnelManager, never()) .closeTunnel( eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), anyInt()); /* Check callback result is RESULT_SUCCESS when onClosed() is called. */ mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onDeactivateDataCallComplete(eq(DataServiceCallback.RESULT_ERROR_INVALID_ARG)); moveTimeForwardAndDispatch(4000); verify(mMockEpdgTunnelManager, never()) .closeTunnel( eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), anyInt()); // No additional callbacks are involved. verify(mMockDataServiceCallback, times(1)).onDeactivateDataCallComplete(anyInt()); } @Test public void testHandoverFailureModeDefault() { DataProfile dp = buildImsDataProfile(); int setupDataReason = DataService.REQUEST_REASON_NORMAL; when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getRemainingRetryTimeMs(eq(TEST_APN_NAME))).thenReturn(5L); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.USER_AUTHENTICATION); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ (setupDataReason == DataService.REQUEST_REASON_HANDOVER), 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, // type IMS true, 13, // LTE false, true, 1 // Transport Wi-Fi ); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); ArgumentCaptor dataCallResponseCaptor = ArgumentCaptor.forClass(DataCallResponse.class); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), dataCallResponseCaptor.capture()); DataCallResponse dataCallResponse = dataCallResponseCaptor.getValue(); assertEquals( dataCallResponse.getHandoverFailureMode(), DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY); assertEquals(dataCallResponse.getCause(), DataFailCause.USER_AUTHENTICATION); assertEquals(dataCallResponse.getRetryDurationMillis(), 5L); } @Test public void testHandoverFailureModeHandover() { DataProfile dp = buildImsDataProfile(); int setupDataReason = DataService.REQUEST_REASON_HANDOVER; when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getRemainingRetryTimeMs(eq(TEST_APN_NAME))).thenReturn(-1L); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); when(mMockErrorPolicyManager.shouldRetryWithInitialAttach(eq(TEST_APN_NAME))) .thenReturn(false); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ (setupDataReason == DataService.REQUEST_REASON_HANDOVER), 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, // type IMS true, 13, // LTE false, true, 1 // Transport Wi-Fi ); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); ArgumentCaptor dataCallResponseCaptor = ArgumentCaptor.forClass(DataCallResponse.class); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), dataCallResponseCaptor.capture()); DataCallResponse dataCallResponse = dataCallResponseCaptor.getValue(); assertEquals( dataCallResponse.getHandoverFailureMode(), DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER); assertEquals(dataCallResponse.getCause(), DataFailCause.ERROR_UNSPECIFIED); assertEquals(dataCallResponse.getRetryDurationMillis(), -1L); } @Test public void testSupportInitialAttachSuccessOnIms() { DataProfile dp = buildImsDataProfile(); int setupDataReason = DataService.REQUEST_REASON_HANDOVER; when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getRemainingRetryTimeMs(eq(TEST_APN_NAME))).thenReturn(-1L); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); when(mMockErrorPolicyManager.shouldRetryWithInitialAttach(eq(TEST_APN_NAME))) .thenReturn(true); // APN = IMS, in idle call state mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CALL_STATE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, CALL_STATE_IDLE) .sendToTarget(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ (setupDataReason == DataService.REQUEST_REASON_HANDOVER), 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, // type IMS true, 13, // LTE false, true, 1 // Transport Wi-Fi ); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); ArgumentCaptor dataCallResponseCaptor = ArgumentCaptor.forClass(DataCallResponse.class); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), dataCallResponseCaptor.capture()); DataCallResponse dataCallResponse = dataCallResponseCaptor.getValue(); // Not on video or voice call assertEquals( DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL, dataCallResponse.getHandoverFailureMode()); } @Test public void testSupportInitialAttachSuccessOnEmergency() { DataProfile dp = buildDataProfile(ApnSetting.TYPE_EMERGENCY); int setupDataReason = DataService.REQUEST_REASON_HANDOVER; when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getRemainingRetryTimeMs(eq(TEST_APN_NAME))).thenReturn(-1L); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); when(mMockErrorPolicyManager.shouldRetryWithInitialAttach(eq(TEST_APN_NAME))) .thenReturn(true); // APN = Emergency, in idle call state mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CALL_STATE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, CALL_STATE_IDLE) .sendToTarget(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ (setupDataReason == DataService.REQUEST_REASON_HANDOVER), 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 512, // type Emergency true, 13, // LTE false, true, 1 // Transport Wi-Fi ); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); ArgumentCaptor dataCallResponseCaptor = ArgumentCaptor.forClass(DataCallResponse.class); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), dataCallResponseCaptor.capture()); DataCallResponse dataCallResponse = dataCallResponseCaptor.getValue(); // Not on video or voice call assertEquals( DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL, dataCallResponse.getHandoverFailureMode()); } @Test public void testSupportInitialAttachOnImsCall() { DataProfile dp = buildImsDataProfile(); int setupDataReason = DataService.REQUEST_REASON_HANDOVER; when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getRemainingRetryTimeMs(eq(TEST_APN_NAME))).thenReturn(-1L); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); when(mMockErrorPolicyManager.shouldRetryWithInitialAttach(eq(TEST_APN_NAME))) .thenReturn(true); // APN = IMS, in call mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CALL_STATE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, TelephonyManager.CALL_STATE_OFFHOOK) .sendToTarget(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null /* linkProperties */, (setupDataReason == DataService.REQUEST_REASON_HANDOVER), 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, // type IMS true, 13, // LTE false, true, 1 // Transport Wi-Fi ); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); ArgumentCaptor dataCallResponseCaptor = ArgumentCaptor.forClass(DataCallResponse.class); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), dataCallResponseCaptor.capture()); DataCallResponse dataCallResponse = dataCallResponseCaptor.getValue(); // In call state assertEquals( DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER, dataCallResponse.getHandoverFailureMode()); } @Test public void testSupportInitialAttachOnEmergencyCall() { DataProfile dp = buildDataProfile(ApnSetting.TYPE_EMERGENCY); int setupDataReason = DataService.REQUEST_REASON_HANDOVER; when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getRemainingRetryTimeMs(eq(TEST_APN_NAME))).thenReturn(-1L); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); when(mMockErrorPolicyManager.shouldRetryWithInitialAttach(eq(TEST_APN_NAME))) .thenReturn(true); // APN = Emergency, in call mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CALL_STATE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, TelephonyManager.CALL_STATE_OFFHOOK) .sendToTarget(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null /* linkProperties */, (setupDataReason == DataService.REQUEST_REASON_HANDOVER), 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 512, // type Emergency true, 13, // LTE false, true, 1 // Transport Wi-Fi ); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); ArgumentCaptor dataCallResponseCaptor = ArgumentCaptor.forClass(DataCallResponse.class); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), dataCallResponseCaptor.capture()); DataCallResponse dataCallResponse = dataCallResponseCaptor.getValue(); // In call state assertEquals( DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER, dataCallResponse.getHandoverFailureMode()); } @Test public void testDnsPrefetching() throws Exception { NetworkCallback networkCallback = getNetworkMonitorCallback(); /* Wifi is connected */ onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); networkCallback.onLinkPropertiesChanged(mMockNetwork, mLinkProperties); mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT, DEFAULT_SLOT_INDEX, 0 /* unused */) .sendToTarget(); mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.WIFI_CALLING_ENABLE_EVENT, DEFAULT_SLOT_INDEX, 0 /* unused */) .sendToTarget(); mTestLooper.dispatchAll(); LinkProperties newLinkProperties = new LinkProperties(); newLinkProperties.setInterfaceName("wlan0"); newLinkProperties.addLinkAddress(mMockIPv4LinkAddress); newLinkProperties.addLinkAddress(mMockIPv6LinkAddress); networkCallback.onLinkPropertiesChanged(mMockNetwork, newLinkProperties); /* Prefetching will be triggered twice. 1. Network connected, CarrierConfig ready, WifiCallingSetting enabled 2. Connection ipFamily changed. */ verify(mMockEpdgSelector, times(2)) .getValidatedServerList( eq(0), eq(EpdgSelector.PROTO_FILTER_IPV4V6), eq(EpdgSelector.SYSTEM_PREFERRED), eq(false), eq(false), eq(mMockNetwork), isNull()); verify(mMockEpdgSelector, times(2)) .getValidatedServerList( eq(0), eq(EpdgSelector.PROTO_FILTER_IPV4V6), eq(EpdgSelector.SYSTEM_PREFERRED), eq(false), eq(true), eq(mMockNetwork), isNull()); } private void advanceCalendarByTimeMs(long time, Calendar calendar) { mMockedCalendarTime += time; if (calendar != null) { calendar.setTimeInMillis(mMockedCalendarTime); } mTestLooper.dispatchAll(); } private DataProfile buildImsDataProfileWithEmptyApnSetting() { return new DataProfile.Builder() .setTrafficDescriptor( new TrafficDescriptor.Builder().setDataNetworkName("").build()) .setType(1) .enable(true) .setPreferred(true) .build(); } private DataProfile buildImsDataProfile() { return buildDataProfile(ApnSetting.TYPE_IMS); } private DataProfile buildDataProfile(int supportedApnTypesBitmask) { return new DataProfile.Builder() .setApnSetting( new ApnSetting.Builder() .setProfileId(1) .setEntryName(TEST_APN_NAME) .setApnName(TEST_APN_NAME) .setProtocol(ApnSetting.PROTOCOL_IPV4V6) .setAuthType(ApnSetting.AUTH_TYPE_NONE) .setUser("") .setPassword("") .setApnTypeBitmask(supportedApnTypesBitmask) .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) .setNetworkTypeBitmask( (int) TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN) .setPersistent(true) .build()) .setType(1) // 3gpp .enable(true) .setPreferred(true) .build(); } private NetworkCapabilities prepareNetworkCapabilitiesForTest( int transportType, int subId, boolean isVcn) { NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder().addTransportType(transportType); if (isVcn) { builder.setTransportInfo(new VcnTransportInfo(subId)); } else { builder.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)); } return builder.build(); } @Test public void testIwlanSetupDataCallFailsWithCellularAndCstDisabled() throws Exception { DataProfile dp = buildImsDataProfile(); /* CST is disabled, and data is on the same sub as the data service provider */ when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(false); NetworkCapabilities nc = prepareNetworkCapabilitiesForTest( TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX, false /* isVcn */); getNetworkMonitorCallback().onCapabilitiesChanged(mMockNetwork, nc); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pdu session id */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, timeout(1000).times(1)) .onSetupDataCallComplete( eq(5 /* DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */), isNull()); } @Test public void testIwlanSetupDataCallFailsWithCellularOnSameSubAndCstEnabled() throws Exception { DataProfile dp = buildImsDataProfile(); /* CST is enabled, but data is on the same sub as the DataServiceProvider */ when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true); NetworkCapabilities nc = prepareNetworkCapabilitiesForTest( TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX, false /* isVcn */); getNetworkMonitorCallback().onCapabilitiesChanged(mMockNetwork, nc); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, timeout(1000).times(1)) .onSetupDataCallComplete( eq(5 /* DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */), isNull()); } @Test public void testIwlanSetupDataCallSucceedsWithCellularOnDifferentSubAndCstEnabled() throws Exception { DataProfile dp = buildImsDataProfile(); /* CST is enabled, but data is on the same sub as the DataServiceProvider */ when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true); NetworkCapabilities nc = prepareNetworkCapabilitiesForTest( TRANSPORT_CELLULAR, DEFAULT_SUB_INDEX + 1, false /* isVcn */); getNetworkMonitorCallback().onCapabilitiesChanged(mMockNetwork, nc); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); /* Check bringUpTunnel() is called. */ verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel( any(TunnelSetupRequest.class), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class)); /* Check callback result is RESULT_SUCCESS when onOpened() is called. */ mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onOpened(TEST_APN_NAME, mMockTunnelLinkProperties); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, times(1)) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), any(DataCallResponse.class)); } @Test public void testIwlanTunnelStatsFailureCounts() { DataProfile dp = buildImsDataProfile(); onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); long count = 3L; for (int i = 0; i < count; i++) { mockTunnelSetupFail(dp); mTestLooper.dispatchAll(); } IwlanDataServiceProvider.IwlanDataTunnelStats stats = mSpyIwlanDataServiceProvider.getTunnelStats(); long result = stats.mTunnelSetupFailureCounts.get(TEST_APN_NAME); assertEquals(result, count); } @Test public void testIwlanTunnelStatsUnsolDownCounts() { DataProfile dp = buildImsDataProfile(); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); long count = 3L; for (int i = 0; i < count; i++) { mockTunnelSetupSuccess(dp, 0, null); mockUnsolTunnelDown(); } IwlanDataServiceProvider.IwlanDataTunnelStats stats = mSpyIwlanDataServiceProvider.getTunnelStats(); long result = stats.mUnsolTunnelDownCounts.get(TEST_APN_NAME); assertEquals(result, count); } @Test public void testIwlanTunnelStats() { DataProfile dp = buildImsDataProfile(); Calendar calendar = mock(Calendar.class); when(calendar.getTime()).thenAnswer(i -> new Date(mMockedCalendarTime)); mSpyIwlanDataServiceProvider.setCalendar(calendar); onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); LongSummaryStatistics tunnelSetupSuccessStats = new LongSummaryStatistics(); LongSummaryStatistics tunnelUpStats = new LongSummaryStatistics(); Date beforeSetup = calendar.getTime(); mockTunnelSetupSuccess(dp, 0, calendar); Date tunnelUp = calendar.getTime(); mockDeactivateTunnel(0, calendar); Date tunnelDown = calendar.getTime(); tunnelSetupSuccessStats.accept(tunnelUp.getTime() - beforeSetup.getTime()); tunnelUpStats.accept(tunnelDown.getTime() - tunnelUp.getTime()); beforeSetup = calendar.getTime(); mockTunnelSetupSuccess(dp, 1000, calendar); tunnelUp = calendar.getTime(); mockDeactivateTunnel(3000, calendar); tunnelDown = calendar.getTime(); tunnelSetupSuccessStats.accept(tunnelUp.getTime() - beforeSetup.getTime()); tunnelUpStats.accept(tunnelDown.getTime() - tunnelUp.getTime()); beforeSetup = calendar.getTime(); mockTunnelSetupSuccess(dp, 600, calendar); tunnelUp = calendar.getTime(); mockDeactivateTunnel(500, calendar); tunnelDown = calendar.getTime(); tunnelSetupSuccessStats.accept(tunnelUp.getTime() - beforeSetup.getTime()); tunnelUpStats.accept(tunnelDown.getTime() - tunnelUp.getTime()); IwlanDataServiceProvider.IwlanDataTunnelStats stats = mSpyIwlanDataServiceProvider.getTunnelStats(); LongSummaryStatistics finalSetupStats = stats.mTunnelSetupSuccessStats.get(TEST_APN_NAME); LongSummaryStatistics finalUpStats = stats.mTunnelUpStats.get(TEST_APN_NAME); assertEquals(tunnelSetupSuccessStats.getAverage(), finalSetupStats.getAverage(), 0); assertEquals(tunnelSetupSuccessStats.getCount(), finalSetupStats.getCount()); assertEquals(tunnelSetupSuccessStats.getMax(), finalSetupStats.getMax(), 0); assertEquals(tunnelUpStats.getAverage(), finalUpStats.getAverage(), 0); assertEquals(tunnelUpStats.getCount(), finalUpStats.getCount()); assertEquals(tunnelUpStats.getMax(), finalUpStats.getMax(), 0); } @Test public void testUnexpectedTunnelClosedIsSuppressed() { mockUnsolTunnelDown(); } @Test public void testIwlanDataServiceHandlerOnUnbind() { DataProfile dp = buildImsDataProfile(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_UP, null /* linkProperties */, false /* isHandover */, 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, // type IMS true, 13, // LTE false, true, 1 // Transport Wi-Fi ); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); // Simulate IwlanDataService.onUnbind() which force close all tunnels mSpyIwlanDataServiceProvider.forceCloseTunnels(EpdgTunnelManager.BRINGDOWN_REASON_UNKNOWN); // Simulate DataService.onUnbind() which remove all IwlanDataServiceProviders mSpyIwlanDataServiceProvider.close(); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, atLeastOnce()) .closeTunnel( eq(TEST_APN_NAME), eq(true), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(EpdgTunnelManager.BRINGDOWN_REASON_UNKNOWN)); assertNotNull(mIwlanDataService.mIwlanDataServiceHandler); // Should not raise NullPointerException mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); } @Test public void testBackToBackOnBindAndOnUnbindDoesNotThrow() { mIwlanDataService.onBind(null); mIwlanDataService.onUnbind(null); } @Test public void testMetricsWhenTunnelClosedWithWrappedException() { DataProfile dp = buildImsDataProfile(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ false /* isHandover */, 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, // type IMS true, 13, // LTE false, true, 1 // Transport Wi-Fi ); MetricsAtom metricsAtom = mSpyIwlanDataServiceProvider.getMetricsAtomByApn(TEST_APN_NAME); assertNotNull(metricsAtom); String exceptionMessage = "Some exception message"; Exception mockException = spy(new IllegalStateException(exceptionMessage)); String firstDeclaringClassName = "test.test.TestClass"; String firstMethodName = "someMethod"; String firstFileName = "TestClass.java"; int firstLineNumber = 12345; StackTraceElement[] stackTraceElements = { new StackTraceElement( firstDeclaringClassName, firstMethodName, firstFileName, firstLineNumber), new StackTraceElement("test", "test", "test.java", 123) }; doReturn(stackTraceElements).when(mockException).getStackTrace(); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(new IkeInternalException(mockException))); mTestLooper.dispatchAll(); var expectedStackFirstFrame = firstDeclaringClassName + "." + firstMethodName + "(" + firstFileName + ":" + firstLineNumber + ")"; assertEquals( mockException.getClass().getCanonicalName(), metricsAtom.getIwlanErrorWrappedClassname()); assertEquals(expectedStackFirstFrame, metricsAtom.getIwlanErrorWrappedStackFirstFrame()); } @Test public void testMetricsWhenTunnelClosedWithoutWrappedException() { DataProfile dp = buildImsDataProfile(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ false /* isHandover */, 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, // type IMS true, 13, // LTE false, true, 1 // Transport Wi-Fi ); MetricsAtom metricsAtom = mSpyIwlanDataServiceProvider.getMetricsAtomByApn(TEST_APN_NAME); assertNotNull(metricsAtom); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed( TEST_APN_NAME, new IwlanError(IwlanError.EPDG_SELECTOR_SERVER_SELECTION_FAILED)); mTestLooper.dispatchAll(); assertEquals(null, metricsAtom.getIwlanErrorWrappedClassname()); assertEquals(null, metricsAtom.getIwlanErrorWrappedStackFirstFrame()); } @Test public void testMetricsWhenTunnelClosedWithErrorCount() { DataProfile dp = buildImsDataProfile(); mSpyIwlanDataServiceProvider.setTunnelState( dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, /* linkProperties */ false /* isHandover */, 1 /* pduSessionId */, true /* isImsOrEmergency */, true /* isDataCallSetupWithN1 */); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, /* type IMS */ true, 13, /* LTE */ false, true, 1 /* Transport Wi-Fi */); MetricsAtom metricsAtom = mSpyIwlanDataServiceProvider.getMetricsAtomByApn(TEST_APN_NAME); assertNotNull(metricsAtom); when(ErrorPolicyManager.getInstance(eq(mMockContext), eq(DEFAULT_SLOT_INDEX))) .thenReturn(mMockErrorPolicyManager); when(mMockErrorPolicyManager.getDataFailCause(eq(TEST_APN_NAME))) .thenReturn(DataFailCause.ERROR_UNSPECIFIED); when(mMockErrorPolicyManager.getLastErrorCountOfSameCause(eq(TEST_APN_NAME))).thenReturn(5); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.IKE_PROTOCOL_EXCEPTION)); mTestLooper.dispatchAll(); assertEquals(5, metricsAtom.getErrorCountOfSameCause()); } private void mockTunnelSetupFail(DataProfile dp) { mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); doReturn(true) .when(mMockEpdgTunnelManager) .bringUpTunnel( any(TunnelSetupRequest.class), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class)); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.IKE_INTERNAL_IO_EXCEPTION)); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, atLeastOnce()) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), any(DataCallResponse.class)); } private void mockTunnelSetupSuccess(DataProfile dp, long setupTime, Calendar calendar) { mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); doReturn(true) .when(mMockEpdgTunnelManager) .bringUpTunnel( any(TunnelSetupRequest.class), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class)); mTestLooper.dispatchAll(); advanceCalendarByTimeMs(setupTime, calendar); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onOpened(TEST_APN_NAME, mMockTunnelLinkProperties); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, atLeastOnce()) .onSetupDataCallComplete( eq(DataServiceCallback.RESULT_SUCCESS), any(DataCallResponse.class)); } private void mockUnsolTunnelDown() { mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.IKE_INTERNAL_IO_EXCEPTION)); mTestLooper.dispatchAll(); } private void mockDeactivateTunnel(long deactivationTime, Calendar calendar) { mSpyIwlanDataServiceProvider.deactivateDataCall( TEST_APN_NAME.hashCode() /* cid: hashcode() of "ims" */, DataService.REQUEST_REASON_NORMAL /* DataService.REQUEST_REASON_NORMAL */, mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, atLeastOnce()) .closeTunnel( eq(TEST_APN_NAME), anyBoolean(), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(BRINGDOWN_REASON_DEACTIVATE_DATA_CALL)); advanceCalendarByTimeMs(deactivationTime, calendar); mSpyIwlanDataServiceProvider .getIwlanTunnelCallback() .onClosed(TEST_APN_NAME, new IwlanError(IwlanError.NO_ERROR)); mTestLooper.dispatchAll(); verify(mMockDataServiceCallback, atLeastOnce()) .onDeactivateDataCallComplete(eq(DataServiceCallback.RESULT_SUCCESS)); } private Object callUnsupportedAppUsageMethod( Object target, String methodName, Class[] parameterTypes, Object[] args) throws Exception { Method method = target.getClass().getDeclaredMethod(methodName, parameterTypes); method.setAccessible(true); return method.invoke(target, args); } @Test public void testNetworkChangeDuringTunnelBringUp_closeTunnel() { DataProfile dp = buildImsDataProfile(); Network newNetwork1 = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork1, mLinkProperties, TRANSPORT_WIFI, DEFAULT_SUB_INDEX); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ true, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ 1, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); /* Check bringUpTunnel() is called. */ verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel( any(TunnelSetupRequest.class), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class)); Network newNetwork2 = createMockNetwork(mLinkProperties); onSystemDefaultNetworkConnected( newNetwork2, mLinkProperties, TRANSPORT_WIFI, DEFAULT_SUB_INDEX); verify(mMockEpdgTunnelManager, times(1)) .closeTunnel( any(), anyBoolean(), any(), any(), eq(BRINGDOWN_REASON_NETWORK_UPDATE_WHEN_TUNNEL_IN_BRINGUP)); } public static TunnelLinkProperties createTunnelLinkProperties() throws Exception { final String IP_ADDRESS = "192.0.2.1"; final String DNS_ADDRESS = "8.8.8.8"; final String PSCF_ADDRESS = "10.159.204.230"; final String INTERFACE_NAME = "ipsec6"; final NetworkSliceInfo SLICE_INFO = NetworkSliceSelectionAssistanceInformation.getSliceInfo(new byte[] {1}); List mInternalAddressList = new ArrayList<>(); List mDNSAddressList = new ArrayList<>(); List mPCSFAddressList = new ArrayList<>(); mInternalAddressList.add(new LinkAddress(InetAddress.getByName(IP_ADDRESS), 3)); mDNSAddressList.add(InetAddress.getByName(DNS_ADDRESS)); mPCSFAddressList.add(InetAddress.getByName(PSCF_ADDRESS)); return TunnelLinkProperties.builder() .setInternalAddresses(mInternalAddressList) .setDnsAddresses(mDNSAddressList) .setPcscfAddresses(mPCSFAddressList) .setIfaceName(INTERFACE_NAME) .setSliceInfo(SLICE_INFO) .build(); } private void setupMockForGetConfig(PersistableBundle bundle) { if (bundle == null) { bundle = new PersistableBundle(); } when(mMockContext.getSystemService(eq(CarrierConfigManager.class))) .thenReturn(mMockCarrierConfigManager); when(mMockCarrierConfigManager.getConfigForSubId(DEFAULT_SLOT_INDEX)).thenReturn(bundle); } private void mockCarrierConfigForN1Mode(boolean supportN1Mode) { PersistableBundle bundle = new PersistableBundle(); if (supportN1Mode) { bundle.putIntArray( CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[] { CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA }); } else { bundle.putIntArray( CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[] {CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA}); } setupMockForGetConfig(bundle); } private void mockCallState(int callState) { onSystemDefaultNetworkConnected(TRANSPORT_CELLULAR); mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CALL_STATE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, callState) .sendToTarget(); mSpyIwlanDataServiceProvider.setMetricsAtom( TEST_APN_NAME, 64, true, TelephonyManager.NETWORK_TYPE_LTE, false, true, 1); } private void updatePreferredNetworkType(long networkTypeBitmask) { mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.PREFERRED_NETWORK_TYPE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, 0 /* unused */, networkTypeBitmask) .sendToTarget(); mTestLooper.dispatchAll(); } @Test public void testIsN1ModeSupported() { PersistableBundle bundle = new PersistableBundle(); bundle.putIntArray( CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[] { CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA }); setupMockForGetConfig(bundle); assertTrue(mSpyIwlanDataServiceProvider.isN1ModeSupported()); bundle.putIntArray( CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[] { CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, }); setupMockForGetConfig(bundle); assertFalse(mSpyIwlanDataServiceProvider.isN1ModeSupported()); } @Test public void testMultipleAllowedNetworkTypeChangeInIdle_updateN1Mode() throws Exception { mockCarrierConfigForN1Mode(true); when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) .thenReturn(true); mockCallState(CALL_STATE_IDLE); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); /* Check closeTunnel() is called. */ verify(mMockEpdgTunnelManager, atLeastOnce()) .closeTunnel( eq(TEST_APN_NAME), eq(true), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(EpdgTunnelManager.BRINGDOWN_REASON_ENABLE_N1_MODE)); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_LTE); verify(mMockEpdgTunnelManager, atLeastOnce()) .closeTunnel( eq(TEST_APN_NAME), eq(true), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(EpdgTunnelManager.BRINGDOWN_REASON_DISABLE_N1_MODE)); } @Test public void testMultipleAllowedNetworkTypeChangeInCall_preferenceChanged_updateAfterCallEnds() throws Exception { mockCarrierConfigForN1Mode(true); when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) .thenReturn(true); mockCallState(CALL_STATE_RINGING); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_LTE); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); verify(mMockEpdgTunnelManager, never()) .closeTunnel(any(), anyBoolean(), any(), any(), anyInt()); // in idle call state mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CALL_STATE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, CALL_STATE_IDLE) .sendToTarget(); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, atLeastOnce()) .closeTunnel( eq(TEST_APN_NAME), eq(true), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class), eq(EpdgTunnelManager.BRINGDOWN_REASON_ENABLE_N1_MODE)); } @Test public void testMultipleAllowedNetworkTypeChangeInCall_preferenceNotChanged_noUpdate() throws Exception { mockCarrierConfigForN1Mode(true); when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) .thenReturn(true); mockCallState(CALL_STATE_RINGING); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_LTE); verify(mMockEpdgTunnelManager, never()) .closeTunnel(any(), anyBoolean(), any(), any(), anyInt()); // in idle call state mIwlanDataService .mIwlanDataServiceHandler .obtainMessage( IwlanEventListener.CALL_STATE_CHANGED_EVENT, DEFAULT_SLOT_INDEX, CALL_STATE_IDLE) .sendToTarget(); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, never()) .closeTunnel(any(), anyBoolean(), any(), any(), anyInt()); } @Test public void testOnAllowedNetworkTypeChange_flagDisabled_noTunnelClose() { mockCarrierConfigForN1Mode(true); when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) .thenReturn(false); mockCallState(CALL_STATE_IDLE); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); verify(mMockEpdgTunnelManager, never()) .closeTunnel(any(), anyBoolean(), any(), any(), anyInt()); } @Test public void testOnAllowedNetworkTypeChange_n1ModeNotSupported_noTunnelClose() { mockCarrierConfigForN1Mode(false); when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) .thenReturn(true); mockCallState(CALL_STATE_IDLE); mockSetupDataCallWithPduSessionId(0); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); verify(mMockEpdgTunnelManager, never()) .closeTunnel(any(), anyBoolean(), any(), any(), anyInt()); } @Test public void testN1ModeNotSupported_tunnelBringupWithNoN1ModeCapability() { mockCarrierConfigForN1Mode(false); when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) .thenReturn(true); mockSetupDataCallWithPduSessionId(1); ArgumentCaptor tunnelSetupRequestCaptor = ArgumentCaptor.forClass(TunnelSetupRequest.class); verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel(tunnelSetupRequestCaptor.capture(), any(), any()); TunnelSetupRequest tunnelSetupRequest = tunnelSetupRequestCaptor.getValue(); assertEquals(PDU_SESSION_ID_UNSET, tunnelSetupRequest.getPduSessionId()); } @Test public void testNoN1ModeCapabilityInOngoingDataCall_newTunnelBringup_doNotIncludeN1() { mockCarrierConfigForN1Mode(true); when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_UPDATE_N1_MODE_ON_UI_CHANGE_BOOL)) .thenReturn(true); mockSetupDataCallWithPduSessionId(0); ArgumentCaptor tunnelSetupRequestCaptor = ArgumentCaptor.forClass(TunnelSetupRequest.class); verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel(tunnelSetupRequestCaptor.capture(), any(), any()); TunnelSetupRequest tunnelSetupRequest = tunnelSetupRequestCaptor.getValue(); assertEquals(PDU_SESSION_ID_UNSET, tunnelSetupRequest.getPduSessionId()); updatePreferredNetworkType(NETWORK_TYPE_BITMASK_NR); mockSetupDataCallWithPduSessionId(1); verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel(tunnelSetupRequestCaptor.capture(), any(), any()); tunnelSetupRequest = tunnelSetupRequestCaptor.getValue(); assertEquals(PDU_SESSION_ID_UNSET, tunnelSetupRequest.getPduSessionId()); } private void mockSetupDataCallWithPduSessionId(int pduSessionId) { DataProfile dp = buildImsDataProfile(); verifySetupDataCallRequestHandled(pduSessionId, dp); } private void verifySetupDataCallRequestHandled(int pduSessionId, DataProfile dp) { onSystemDefaultNetworkConnected( mMockNetwork, mLinkProperties, TRANSPORT_WIFI, INVALID_SUB_INDEX); mSpyIwlanDataServiceProvider.setupDataCall( AccessNetworkType.IWLAN, /* AccessNetworkType */ dp, /* dataProfile */ false, /* isRoaming */ false, /* allowRoaming */ DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */ null, /* LinkProperties */ pduSessionId, /* pduSessionId */ null, /* sliceInfo */ null, /* trafficDescriptor */ true, /* matchAllRuleAllowed */ mMockDataServiceCallback); mTestLooper.dispatchAll(); verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel( any(TunnelSetupRequest.class), any(IwlanTunnelCallback.class), any(IwlanTunnelMetricsImpl.class)); } @Test public void testN1ModeForEmergencySession() { int pduSessionId = 5; DataProfile dp = buildDataProfile(ApnSetting.TYPE_EMERGENCY); verifySetupDataCallRequestHandled(pduSessionId, dp); ArgumentCaptor tunnelSetupRequestCaptor = ArgumentCaptor.forClass(TunnelSetupRequest.class); verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel(tunnelSetupRequestCaptor.capture(), any(), any()); TunnelSetupRequest tunnelSetupRequest = tunnelSetupRequestCaptor.getValue(); assertEquals(pduSessionId, tunnelSetupRequest.getPduSessionId()); } @Test public void testN1ModeExclusionForEmergencySession() { when(IwlanCarrierConfig.getConfigBoolean( mMockContext, DEFAULT_SLOT_INDEX, IwlanCarrierConfig.KEY_N1_MODE_EXCLUSION_FOR_EMERGENCY_SESSION_BOOL)) .thenReturn(true); DataProfile dp = buildDataProfile(ApnSetting.TYPE_EMERGENCY); verifySetupDataCallRequestHandled(5 /* pduSessionId */, dp); ArgumentCaptor tunnelSetupRequestCaptor = ArgumentCaptor.forClass(TunnelSetupRequest.class); verify(mMockEpdgTunnelManager, times(1)) .bringUpTunnel(tunnelSetupRequestCaptor.capture(), any(), any()); TunnelSetupRequest tunnelSetupRequest = tunnelSetupRequestCaptor.getValue(); assertEquals(PDU_SESSION_ID_UNSET, tunnelSetupRequest.getPduSessionId()); } }