| /* |
| * Copyright 2021 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.android.internal.telephony.data; |
| |
| import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; |
| |
| import static com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; |
| import static com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.common.truth.Truth.assertWithMessage; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertSame; |
| import static org.junit.Assert.assertThrows; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyBoolean; |
| import static org.mockito.ArgumentMatchers.anyInt; |
| import static org.mockito.ArgumentMatchers.anyString; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.Mockito.clearInvocations; |
| import static org.mockito.Mockito.doAnswer; |
| import static org.mockito.Mockito.doReturn; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.annotation.NonNull; |
| import android.net.ConnectivityManager; |
| import android.net.InetAddresses; |
| import android.net.LinkAddress; |
| import android.net.LinkProperties; |
| import android.net.NetworkCapabilities; |
| import android.net.NetworkPolicyManager; |
| import android.net.NetworkRequest; |
| import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener; |
| import android.net.vcn.VcnNetworkPolicyResult; |
| import android.os.AsyncResult; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.PersistableBundle; |
| import android.os.RegistrantList; |
| import android.provider.Telephony; |
| import android.telephony.AccessNetworkConstants; |
| import android.telephony.AccessNetworkConstants.AccessNetworkType; |
| import android.telephony.AccessNetworkConstants.TransportType; |
| import android.telephony.Annotation; |
| import android.telephony.Annotation.DataFailureCause; |
| import android.telephony.Annotation.NetCapability; |
| import android.telephony.Annotation.NetworkType; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.DataFailCause; |
| import android.telephony.DataSpecificRegistrationInfo; |
| import android.telephony.LteVopsSupportInfo; |
| import android.telephony.NetworkRegistrationInfo; |
| import android.telephony.NetworkRegistrationInfo.RegistrationState; |
| import android.telephony.ServiceState; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.SubscriptionPlan; |
| import android.telephony.TelephonyDisplayInfo; |
| import android.telephony.TelephonyManager; |
| import android.telephony.data.ApnSetting; |
| import android.telephony.data.DataCallResponse; |
| import android.telephony.data.DataCallResponse.LinkStatus; |
| import android.telephony.data.DataProfile; |
| import android.telephony.data.DataService; |
| import android.telephony.data.DataServiceCallback; |
| import android.telephony.data.ThrottleStatus; |
| import android.telephony.data.TrafficDescriptor; |
| import android.telephony.data.TrafficDescriptor.OsAppId; |
| import android.telephony.ims.ImsManager; |
| import android.telephony.ims.ImsMmTelManager; |
| import android.telephony.ims.ImsRcsManager; |
| import android.telephony.ims.ImsReasonInfo; |
| import android.telephony.ims.ImsRegistrationAttributes; |
| import android.telephony.ims.ImsStateCallback; |
| import android.telephony.ims.RegistrationManager.RegistrationCallback; |
| import android.telephony.ims.feature.ImsFeature; |
| import android.telephony.ims.stub.ImsRegistrationImplBase; |
| import android.testing.AndroidTestingRunner; |
| import android.testing.TestableLooper; |
| import android.util.ArraySet; |
| import android.util.SparseArray; |
| |
| import com.android.internal.telephony.ISub; |
| import com.android.internal.telephony.MultiSimSettingController; |
| import com.android.internal.telephony.Phone; |
| import com.android.internal.telephony.PhoneConstants; |
| import com.android.internal.telephony.PhoneFactory; |
| import com.android.internal.telephony.RIL; |
| import com.android.internal.telephony.TelephonyTest; |
| import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; |
| import com.android.internal.telephony.data.DataEvaluation.DataDisallowedReason; |
| import com.android.internal.telephony.data.DataNetworkController.HandoverRule; |
| import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback; |
| import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback; |
| import com.android.internal.telephony.ims.ImsResolver; |
| import com.android.internal.telephony.subscription.SubscriptionInfoInternal; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.Mockito; |
| |
| import java.lang.reflect.Field; |
| import java.time.Period; |
| import java.time.ZonedDateTime; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.Executor; |
| |
| @RunWith(AndroidTestingRunner.class) |
| @TestableLooper.RunWithLooper |
| public class DataNetworkControllerTest extends TelephonyTest { |
| private static final String IPV4_ADDRESS = "10.0.2.15"; |
| private static final String IPV6_ADDRESS = "2607:fb90:a620:651d:eabe:f8da:c107:44be"; |
| |
| private static final String FAKE_MMTEL_PACKAGE = "fake.mmtel.package"; |
| private static final String FAKE_RCS_PACKAGE = "fake.rcs.package"; |
| |
| // Events |
| private static final int EVENT_SIM_STATE_CHANGED = 9; |
| private static final int EVENT_REEVALUATE_EXISTING_DATA_NETWORKS = 16; |
| private static final int EVENT_VOICE_CALL_ENDED = 18; |
| private static final int EVENT_SUBSCRIPTION_OVERRIDE = 23; |
| |
| // Mocked classes |
| private PhoneSwitcher mMockedPhoneSwitcher; |
| protected ISub mMockedIsub; |
| private DataNetworkControllerCallback mMockedDataNetworkControllerCallback; |
| private DataRetryManagerCallback mMockedDataRetryManagerCallback; |
| private ImsResolver mMockedImsResolver; |
| |
| private ImsManager mMockedImsManager; |
| private ImsMmTelManager mMockedImsMmTelManager; |
| private ImsRcsManager mMockedImsRcsManager; |
| private ImsStateCallback mMmtelStateCallback; |
| private ImsStateCallback mRcsStateCallback; |
| private RegistrationCallback mMmtelRegCallback; |
| private RegistrationCallback mRcsRegCallback; |
| private SubscriptionInfo mMockSubInfo; |
| |
| private int mNetworkRequestId = 0; |
| |
| private final SparseArray<DataServiceManager> mMockedDataServiceManagers = new SparseArray<>(); |
| private final SparseArray<RegistrantList> mDataCallListChangedRegistrants = new SparseArray<>(); |
| private DataNetworkController mDataNetworkControllerUT; |
| private PersistableBundle mCarrierConfig; |
| private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; |
| |
| private AccessNetworksManagerCallback mAccessNetworksManagerCallback; |
| private LinkBandwidthEstimatorCallback mLinkBandwidthEstimatorCallback; |
| |
| private final DataProfile mGeneralPurposeDataProfile = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setId(2163) |
| .setOperatorNumeric("12345") |
| .setEntryName("internet_supl_mms_apn") |
| .setApnName("internet_supl_mms_apn") |
| .setUser("user") |
| .setPassword("passwd") |
| .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL |
| | ApnSetting.TYPE_MMS) |
| .setProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IP) |
| .setCarrierEnabled(true) |
| .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_NR |
| | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT)) |
| .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT |
| | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS |
| | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) |
| .setProfileId(1234) |
| .setMaxConns(321) |
| .setWaitTime(456) |
| .setMaxConnsTime(789) |
| .build()) |
| .setPreferred(false) |
| .build(); |
| |
| // The same data profile but with different auto generated ID, should be considered the same as |
| // mGeneralPurposeDataProfile |
| private final DataProfile mDuplicatedGeneralPurposeDataProfile = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setId(3612) |
| .setOperatorNumeric("12345") |
| .setEntryName("internet_supl_mms_apn") |
| .setApnName("internet_supl_mms_apn") |
| .setUser("user") |
| .setPassword("passwd") |
| .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL |
| | ApnSetting.TYPE_MMS) |
| .setProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IP) |
| .setCarrierEnabled(true) |
| .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT)) |
| .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT |
| | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS |
| | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) |
| .setProfileId(1234) |
| .setMaxConns(321) |
| .setWaitTime(456) |
| .setMaxConnsTime(789) |
| .build()) |
| .setPreferred(false) |
| .build(); |
| |
| // Created to test preferred data profiles that apply to different network types |
| private final DataProfile mGeneralPurposeDataProfileAlternative = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setId(2161) |
| .setOperatorNumeric("12345") |
| .setEntryName("internet_supl_mms_apn") |
| .setApnName("internet_supl_mms_apn") |
| .setUser("user") |
| .setPassword("passwd") |
| .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL |
| | ApnSetting.TYPE_MMS) |
| .setProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IP) |
| .setCarrierEnabled(true) |
| .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_NR |
| | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT)) |
| .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT |
| | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS |
| | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) |
| .setProfileId(4321) |
| .setMaxConns(321) |
| .setWaitTime(456) |
| .setMaxConnsTime(789) |
| .build()) |
| .setPreferred(false) |
| .build(); |
| |
| private final DataProfile mImsCellularDataProfile = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setId(2164) |
| .setOperatorNumeric("12345") |
| .setEntryName("ims_apn") |
| .setApnName("ims_apn") |
| .setUser("user") |
| .setPassword("passwd") |
| .setApnTypeBitmask(ApnSetting.TYPE_IMS) |
| .setProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IP) |
| .setCarrierEnabled(true) |
| .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT)) |
| .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT |
| | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN |
| | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS |
| | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) |
| .setProfileId(1235) |
| .setMaxConns(321) |
| .setWaitTime(456) |
| .setMaxConnsTime(789) |
| .build()) |
| .setPreferred(false) |
| .build(); |
| |
| private final DataProfile mImsIwlanDataProfile = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setId(2164) |
| .setOperatorNumeric("12345") |
| .setEntryName("ims_apn") |
| .setApnName("ims_apn") |
| .setUser("user") |
| .setPassword("passwd") |
| .setApnTypeBitmask(ApnSetting.TYPE_IMS) |
| .setProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setCarrierEnabled(true) |
| .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN)) |
| .setProfileId(1235) |
| .setMaxConns(321) |
| .setWaitTime(456) |
| .setMaxConnsTime(789) |
| .build()) |
| .setPreferred(false) |
| .build(); |
| |
| private final DataProfile mEmergencyDataProfile = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setEntryName("DEFAULT EIMS") |
| .setId(2165) |
| .setProtocol(ApnSetting.PROTOCOL_IPV4V6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) |
| .setApnName("sos") |
| .setApnTypeBitmask(ApnSetting.TYPE_EMERGENCY) |
| .setCarrierEnabled(true) |
| .setApnSetId(Telephony.Carriers.MATCH_ALL_APN_SET_ID) |
| .build()) |
| .build(); |
| |
| private final DataProfile mFotaDataProfile = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setId(2166) |
| .setOperatorNumeric("12345") |
| .setEntryName("fota_apn") |
| .setApnName("fota_apn") |
| .setUser("user") |
| .setPassword("passwd") |
| .setApnTypeBitmask(ApnSetting.TYPE_FOTA) |
| .setProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IP) |
| .setCarrierEnabled(true) |
| .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | (int) TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT) |
| .setProfileId(1236) |
| .setMaxConns(321) |
| .setWaitTime(456) |
| .setMaxConnsTime(789) |
| .build()) |
| .setPreferred(false) |
| .build(); |
| |
| private final DataProfile mTetheringDataProfile = new DataProfile.Builder() |
| .setApnSetting(new ApnSetting.Builder() |
| .setId(2167) |
| .setOperatorNumeric("12345") |
| .setEntryName("dun_apn") |
| .setApnName("dun_apn") |
| .setUser("user") |
| .setPassword("passwd") |
| .setApnTypeBitmask(ApnSetting.TYPE_DUN | ApnSetting.TYPE_DEFAULT) |
| .setProtocol(ApnSetting.PROTOCOL_IPV6) |
| .setRoamingProtocol(ApnSetting.PROTOCOL_IP) |
| .setCarrierEnabled(true) |
| .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE |
| | (int) TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT) |
| .setProfileId(1236) |
| .setMaxConns(321) |
| .setWaitTime(456) |
| .setMaxConnsTime(789) |
| .build()) |
| .setPreferred(false) |
| .build(); |
| |
| private final DataProfile mEnterpriseDataProfile = new DataProfile.Builder() |
| .setTrafficDescriptor(new TrafficDescriptor(null, |
| new TrafficDescriptor.OsAppId(TrafficDescriptor.OsAppId.ANDROID_OS_ID, |
| "ENTERPRISE", 1).getBytes())) |
| .build(); |
| |
| private final DataProfile mLowLatencyDataProfile = new DataProfile.Builder() |
| .setTrafficDescriptor(new TrafficDescriptor(null, |
| new TrafficDescriptor.OsAppId(TrafficDescriptor.OsAppId.ANDROID_OS_ID, |
| "PRIORITIZE_LATENCY", 1).getBytes())) |
| .build(); |
| |
| /** Data call response map. The first key is the transport type, the second key is the cid. */ |
| private final Map<Integer, Map<Integer, DataCallResponse>> mDataCallResponses = new HashMap<>(); |
| |
| private @NonNull DataCallResponse createDataCallResponse(int cid, @LinkStatus int linkStatus) { |
| return createDataCallResponse(cid, linkStatus, Collections.emptyList()); |
| } |
| |
| private @NonNull DataCallResponse createDataCallResponse(int cid, @LinkStatus int linkStatus, |
| @NonNull List<TrafficDescriptor> tdList) { |
| return new DataCallResponse.Builder() |
| .setCause(0) |
| .setRetryDurationMillis(-1L) |
| .setId(cid) |
| .setLinkStatus(linkStatus) |
| .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) |
| .setInterfaceName("ifname" + cid) |
| .setAddresses(Arrays.asList( |
| new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32), |
| new LinkAddress(IPV6_ADDRESS + "/64"))) |
| .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), |
| InetAddresses.parseNumericAddress("fd00:976a::9"))) |
| .setGatewayAddresses(Arrays.asList( |
| InetAddresses.parseNumericAddress("10.0.2.15"), |
| InetAddresses.parseNumericAddress("fe80::2"))) |
| .setPcscfAddresses(Arrays.asList( |
| InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), |
| InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), |
| InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) |
| .setMtu(1500) |
| .setMtuV4(1500) |
| .setMtuV6(1500) |
| .setPduSessionId(1) |
| .setQosBearerSessions(new ArrayList<>()) |
| .setTrafficDescriptors(tdList) |
| .build(); |
| } |
| |
| private void setFailedSetupDataResponse(DataServiceManager dsm, @DataFailureCause int cause, |
| long retryMillis, boolean forHandover) { |
| setFailedSetupDataResponse(dsm, cause, retryMillis, forHandover, 0); |
| } |
| |
| private void setFailedSetupDataResponse(DataServiceManager dsm, @DataFailureCause int cause, |
| long retryMillis, boolean forHandover, long delay) { |
| doAnswer(invocation -> { |
| final Message msg = (Message) invocation.getArguments()[10]; |
| |
| DataCallResponse response = new DataCallResponse.Builder() |
| .setCause(cause) |
| .setRetryDurationMillis(retryMillis) |
| .setHandoverFailureMode( |
| DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER) |
| .build(); |
| msg.getData().putParcelable("data_call_response", response); |
| msg.arg1 = DataServiceCallback.RESULT_SUCCESS; |
| msg.getTarget().sendMessageDelayed(msg, delay); |
| return null; |
| }).when(dsm).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), |
| anyBoolean(), forHandover ? eq(DataService.REQUEST_REASON_HANDOVER) |
| : eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), |
| anyBoolean(), any(Message.class)); |
| } |
| |
| private void setSuccessfulSetupDataResponse(DataServiceManager dsm, DataCallResponse response) { |
| doAnswer(invocation -> { |
| final Message msg = (Message) invocation.getArguments()[10]; |
| |
| int transport = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; |
| if (dsm == mMockedWwanDataServiceManager) { |
| transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; |
| } else if (dsm == mMockedWlanDataServiceManager) { |
| transport = AccessNetworkConstants.TRANSPORT_TYPE_WLAN; |
| } |
| mDataCallResponses.computeIfAbsent(transport, v -> new HashMap<>()); |
| mDataCallResponses.get(transport).put(response.getId(), response); |
| msg.getData().putParcelable("data_call_response", response); |
| msg.arg1 = DataServiceCallback.RESULT_SUCCESS; |
| msg.sendToTarget(); |
| |
| mDataCallListChangedRegistrants.get(transport).notifyRegistrants( |
| new AsyncResult(transport, new ArrayList<>(mDataCallResponses.get( |
| transport).values()), null)); |
| return null; |
| }).when(dsm).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), |
| anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| any(Message.class)); |
| } |
| |
| private void setSuccessfulSetupDataResponse(DataServiceManager dsm, int cid) { |
| setSuccessfulSetupDataResponse(dsm, cid, 0L); |
| } |
| |
| private void setSuccessfulSetupDataResponse(DataServiceManager dsm, int cid, long delay) { |
| doAnswer(invocation -> { |
| final Message msg = (Message) invocation.getArguments()[10]; |
| |
| DataCallResponse response = createDataCallResponse(cid, |
| DataCallResponse.LINK_STATUS_ACTIVE); |
| int transport = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; |
| if (dsm == mMockedWwanDataServiceManager) { |
| transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; |
| } else if (dsm == mMockedWlanDataServiceManager) { |
| transport = AccessNetworkConstants.TRANSPORT_TYPE_WLAN; |
| } |
| mDataCallResponses.computeIfAbsent(transport, v -> new HashMap<>()); |
| mDataCallResponses.get(transport).put(cid, response); |
| msg.getData().putParcelable("data_call_response", response); |
| msg.arg1 = DataServiceCallback.RESULT_SUCCESS; |
| msg.getTarget().sendMessageDelayed(msg, delay); |
| |
| final int t = transport; |
| msg.getTarget().postDelayed(() -> { |
| mDataCallListChangedRegistrants.get(t).notifyRegistrants( |
| new AsyncResult(t, new ArrayList<>(mDataCallResponses.get( |
| t).values()), null)); |
| |
| }, delay + 100); |
| return null; |
| }).when(dsm).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), |
| anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| any(Message.class)); |
| } |
| |
| private void clearCallbacks() throws Exception { |
| Field field = DataNetworkController.class |
| .getDeclaredField("mDataNetworkControllerCallbacks"); |
| field.setAccessible(true); |
| ((Set<DataNetworkControllerCallback>) field.get(mDataNetworkControllerUT)).clear(); |
| } |
| |
| private void carrierConfigChanged() { |
| // Trigger carrier config reloading |
| mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* logicalSlotIndex */, |
| SubscriptionManager.INVALID_SUBSCRIPTION_ID, |
| TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); |
| |
| processAllMessages(); |
| } |
| |
| private void setImsRegistered(boolean registered, |
| @ImsRegistrationImplBase.ImsRegistrationTech int regTech) { |
| if (registered) { |
| final ArraySet<String> features = new ArraySet<>(); |
| features.add("feature1"); |
| features.add("feature2"); |
| ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(regTech) |
| .setFeatureTags(features).build(); |
| |
| mMmtelRegCallback.onRegistered(attr); |
| } else { |
| ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_ILLEGAL_STATE, -1, ""); |
| mMmtelRegCallback.onUnregistered(info); |
| } |
| } |
| |
| private void setRcsRegistered(boolean registered, |
| @ImsRegistrationImplBase.ImsRegistrationTech int regTech) { |
| if (registered) { |
| final ArraySet<String> features = new ArraySet<>(); |
| features.add("feature1"); |
| features.add("feature2"); |
| ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(regTech) |
| .setFeatureTags(features).build(); |
| |
| mRcsRegCallback.onRegistered(attr); |
| } else { |
| ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_ILLEGAL_STATE, -1, ""); |
| mRcsRegCallback.onUnregistered(info); |
| } |
| } |
| |
| private void serviceStateChanged(@NetworkType int networkType, |
| @RegistrationState int regState) { |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) |
| .build(); |
| |
| serviceStateChanged(networkType, regState, regState, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); |
| } |
| |
| private void serviceStateChanged(@NetworkType int networkType, |
| @RegistrationState int regState, DataSpecificRegistrationInfo dsri) { |
| serviceStateChanged(networkType, regState, regState, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); |
| } |
| |
| private void serviceStateChanged(@NetworkType int networkType, |
| @RegistrationState int dataRegState, @RegistrationState int voiceRegState, |
| @RegistrationState int iwlanRegState, DataSpecificRegistrationInfo dsri) { |
| ServiceState ss = createSS(networkType, networkType, dataRegState, voiceRegState, |
| iwlanRegState, dsri); |
| |
| doReturn(ss).when(mSST).getServiceState(); |
| doReturn(ss).when(mPhone).getServiceState(); |
| |
| mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| } |
| |
| private ServiceState createSS(@NetworkType int dataNetworkType, |
| @NetworkType int voiceNetworkType, |
| @RegistrationState int dataRegState, @RegistrationState int voiceRegState, |
| @RegistrationState int iwlanRegState, DataSpecificRegistrationInfo dsri) { |
| if (dsri == null) { |
| dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) |
| .build(); |
| } |
| |
| ServiceState ss = new ServiceState(); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(dataNetworkType) |
| .setRegistrationState(dataRegState) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setDataSpecificInfo(dsri) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) |
| .setRegistrationState(iwlanRegState) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(voiceNetworkType) |
| .setRegistrationState(voiceRegState) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_CS) |
| .build()); |
| |
| ss.setDataRoamingFromRegistration(dataRegState |
| == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| processServiceStateRegStateForTest(ss); |
| return ss; |
| } |
| |
| // set SS reg state base on SST impl, where WLAN overrides WWAN's data reg. |
| private void processServiceStateRegStateForTest(ServiceState ss) { |
| int wlanRegState = ss.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN).getRegistrationState(); |
| if (wlanRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { |
| ss.setDataRegState(ServiceState.STATE_IN_SERVICE); |
| } else { |
| int cellularRegState = ss.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getRegistrationState(); |
| int dataState = (cellularRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME |
| || cellularRegState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) |
| ? ServiceState.STATE_IN_SERVICE : ServiceState.STATE_OUT_OF_SERVICE; |
| ss.setDataRegState(dataState); |
| } |
| int voiceRegState = ss.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_CS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getRegistrationState(); |
| int voiceState = (voiceRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME |
| || voiceRegState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) |
| ? ServiceState.STATE_IN_SERVICE : ServiceState.STATE_OUT_OF_SERVICE; |
| ss.setVoiceRegState(voiceState); |
| } |
| |
| private void updateTransport(@NetCapability int capability, @TransportType int transport) { |
| doReturn(transport).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(capability); |
| mAccessNetworksManagerCallback.onPreferredTransportChanged(capability); |
| processAllMessages(); |
| } |
| |
| private void setVcnManagerPolicy(boolean vcnManaged, boolean shouldTearDown) { |
| doAnswer(invocation -> { |
| final NetworkCapabilities networkCapabilities = |
| (NetworkCapabilities) invocation.getArguments()[0]; |
| if (vcnManaged) { |
| networkCapabilities.removeCapability( |
| NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); |
| } else { |
| networkCapabilities.addCapability( |
| NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); |
| } |
| return new VcnNetworkPolicyResult( |
| shouldTearDown, networkCapabilities); |
| }).when(mVcnManager).applyVcnNetworkPolicy(any(NetworkCapabilities.class), |
| any(LinkProperties.class)); |
| } |
| |
| private void initializeConfig() { |
| mCarrierConfig = mContextFixture.getCarrierConfigBundle(); |
| when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mCarrierConfig); |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_TELEPHONY_NETWORK_CAPABILITY_PRIORITIES_STRING_ARRAY, |
| new String[]{ |
| "eims:90", "supl:80", "mms:70", "xcap:70", "cbs:50", "mcx:50", "fota:50", |
| "ims:40", "dun:30", "enterprise:20", "internet:20" |
| }); |
| mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, |
| new String[]{"default", "mms", "dun", "supl", "enterprise"}); |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, |
| new String[]{"default", "mms", "dun", "supl", "enterprise"}); |
| |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY, |
| new String[]{ |
| "capabilities=eims, retry_interval=1000, maximum_retries=20", |
| "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|" |
| + "-3|65543|65547|2252|2253|2254, retry_interval=2500", |
| "capabilities=mms|supl|cbs, retry_interval=2000", |
| "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|" |
| + "5000|10000|15000|20000|40000|60000|120000|240000|" |
| + "600000|1200000|1800000, maximum_retries=20" |
| }); |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY, |
| new String[] {"retry_interval=1000|2000|4000|8000|16000, maximum_retries=5" |
| }); |
| |
| mCarrierConfig.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 1234); |
| |
| mCarrierConfig.putBoolean(CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, |
| true); |
| mCarrierConfig.putStringArray(CarrierConfigManager.KEY_UNMETERED_NETWORK_TYPES_STRING_ARRAY, |
| new String[] {"NR_NSA", "NR_NSA_MMWAVE", "NR_SA", "NR_SA_MMWAVE"}); |
| |
| mCarrierConfig.putIntArray(CarrierConfigManager.KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY, |
| new int[]{TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT, |
| TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A, |
| TelephonyManager.NETWORK_TYPE_EVDO_B}); |
| |
| mCarrierConfig.putIntArray(CarrierConfigManager |
| .KEY_CAPABILITIES_EXEMPT_FROM_SINGLE_DC_CHECK_INT_ARRAY, |
| new int[]{NetworkCapabilities.NET_CAPABILITY_IMS}); |
| |
| mContextFixture.putResource(com.android.internal.R.string.config_bandwidthEstimateSource, |
| "bandwidth_estimator"); |
| |
| mContextFixture.putIntResource(com.android.internal.R.integer |
| .config_delay_for_ims_dereg_millis, 3000); |
| mContextFixture.putBooleanResource(com.android.internal.R.bool |
| .config_enable_iwlan_handover_policy, true); |
| mContextFixture.putBooleanResource(com.android.internal.R.bool |
| .config_enhanced_iwlan_handover_check, true); |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| logd("DataNetworkControllerTest +Setup!"); |
| super.setUp(getClass().getSimpleName()); |
| mMockedPhoneSwitcher = Mockito.mock(PhoneSwitcher.class); |
| mMockedIsub = Mockito.mock(ISub.class); |
| mMockedImsManager = mContext.getSystemService(ImsManager.class); |
| mMockedImsMmTelManager = Mockito.mock(ImsMmTelManager.class); |
| mMockedImsRcsManager = Mockito.mock(ImsRcsManager.class); |
| mMockedImsResolver = Mockito.mock(ImsResolver.class); |
| mMockedDataNetworkControllerCallback = Mockito.mock(DataNetworkControllerCallback.class); |
| mMockedDataRetryManagerCallback = Mockito.mock(DataRetryManagerCallback.class); |
| mMockSubInfo = Mockito.mock(SubscriptionInfo.class); |
| when(mTelephonyComponentFactory.makeDataSettingsManager(any(Phone.class), |
| any(DataNetworkController.class), any(Looper.class), |
| any(DataSettingsManager.DataSettingsManagerCallback.class))).thenCallRealMethod(); |
| doReturn(mMockedImsMmTelManager).when(mMockedImsManager).getImsMmTelManager(anyInt()); |
| doReturn(mMockedImsRcsManager).when(mMockedImsManager).getImsRcsManager(anyInt()); |
| |
| initializeConfig(); |
| mMockedDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, |
| mMockedWwanDataServiceManager); |
| mMockedDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, |
| mMockedWlanDataServiceManager); |
| |
| replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mMockedPhoneSwitcher); |
| doReturn(1).when(mMockedIsub).getDefaultDataSubId(); |
| doReturn(mMockedIsub).when(mIBinder).queryLocalInterface(anyString()); |
| doReturn(mPhone).when(mPhone).getImsPhone(); |
| mServiceManagerMockedServices.put("isub", mIBinder); |
| doReturn(new SubscriptionPlan[]{}).when(mNetworkPolicyManager) |
| .getSubscriptionPlans(anyInt(), any()); |
| doReturn(true).when(mSST).getDesiredPowerState(); |
| doReturn(true).when(mSST).getPowerStateFromCarrier(); |
| doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); |
| doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); |
| doReturn(new SubscriptionInfoInternal.Builder().setId(1).build()) |
| .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); |
| |
| List<SubscriptionInfo> infoList = new ArrayList<>(); |
| infoList.add(mMockSubInfo); |
| doReturn(0).when(mSubscriptionManagerService).getPhoneId(1); |
| doReturn(1).when(mSubscriptionManagerService).getPhoneId(2); |
| |
| for (int transport : new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) { |
| mDataCallListChangedRegistrants.put(transport, new RegistrantList()); |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers.get(transport), 1); |
| doAnswer(invocation -> { |
| int cid = (int) invocation.getArguments()[0]; |
| Message msg = (Message) invocation.getArguments()[2]; |
| msg.sendToTarget(); |
| mDataCallResponses.get(transport).remove(cid); |
| mDataCallListChangedRegistrants.get(transport).notifyRegistrants( |
| new AsyncResult(transport, new ArrayList<>(mDataCallResponses.get( |
| transport).values()), null)); |
| return null; |
| }).when(mMockedDataServiceManagers.get(transport)).deactivateDataCall( |
| anyInt(), anyInt(), any(Message.class)); |
| |
| doAnswer(invocation -> { |
| Handler h = (Handler) invocation.getArguments()[0]; |
| int what = (int) invocation.getArguments()[1]; |
| mDataCallListChangedRegistrants.get(transport).addUnique(h, what, transport); |
| return null; |
| }).when(mMockedDataServiceManagers.get(transport)).registerForDataCallListChanged(any( |
| Handler.class), anyInt()); |
| |
| doAnswer(invocation -> { |
| Message msg = (Message) invocation.getArguments()[1]; |
| msg.sendToTarget(); |
| return null; |
| }).when(mMockedDataServiceManagers.get(transport)).startHandover(anyInt(), |
| any(Message.class)); |
| |
| doAnswer(invocation -> { |
| Message msg = (Message) invocation.getArguments()[1]; |
| msg.sendToTarget(); |
| return null; |
| }).when(mMockedDataServiceManagers.get(transport)).cancelHandover(anyInt(), |
| any(Message.class)); |
| } |
| |
| doReturn(-1).when(mPhone).getSubId(); |
| |
| // Capture listener to emulate the carrier config change notification used later |
| ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = |
| ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); |
| // Note that creating a "real" data network controller will also result in creating |
| // real DataRetryManager, DataConfigManager, etc...Normally in unit test we should isolate |
| // other modules and make them mocked, but only focusing on testing the unit we would like |
| // to test, in this case, DataNetworkController. But since there are too many interactions |
| // between DataNetworkController and its sub-modules, we intend to make those modules "real" |
| // as well, except some modules below we replaced with mocks. |
| mDataNetworkControllerUT = new DataNetworkController(mPhone, Looper.myLooper()); |
| // First two come from DataServiceManager and the third comes from DataConfigManager which |
| // is what we want to capture and assign to mCarrierConfigChangeListener |
| verify(mCarrierConfigManager, times(3)).registerCarrierConfigChangeListener(any(), |
| listenerArgumentCaptor.capture()); |
| mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(2); |
| assertThat(mCarrierConfigChangeListener).isNotNull(); |
| doReturn(mDataNetworkControllerUT).when(mPhone).getDataNetworkController(); |
| |
| doReturn(1).when(mPhone).getSubId(); |
| mDataNetworkControllerUT.obtainMessage(15/*EVENT_SUBSCRIPTION_CHANGED*/).sendToTarget(); |
| |
| processAllMessages(); |
| // Clear the callbacks created by the real sub-modules created by DataNetworkController. |
| clearCallbacks(); |
| SparseArray<DataServiceManager> dataServiceManagers = new SparseArray<>(); |
| dataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, |
| mMockedWwanDataServiceManager); |
| dataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, |
| mMockedWlanDataServiceManager); |
| replaceInstance(DataNetworkController.class, "mDataServiceManagers", |
| mDataNetworkControllerUT, dataServiceManagers); |
| replaceInstance(DataNetworkController.class, "mDataProfileManager", |
| mDataNetworkControllerUT, mDataProfileManager); |
| replaceInstance(DataNetworkController.class, "mAccessNetworksManager", |
| mDataNetworkControllerUT, mAccessNetworksManager); |
| replaceInstance(ImsResolver.class, "sInstance", null, mMockedImsResolver); |
| |
| ArgumentCaptor<AccessNetworksManagerCallback> callbackCaptor = |
| ArgumentCaptor.forClass(AccessNetworksManagerCallback.class); |
| verify(mAccessNetworksManager).registerCallback(callbackCaptor.capture()); |
| mAccessNetworksManagerCallback = callbackCaptor.getValue(); |
| |
| ArgumentCaptor<LinkBandwidthEstimatorCallback> linkBandwidthEstimatorCallbackCaptor = |
| ArgumentCaptor.forClass(LinkBandwidthEstimatorCallback.class); |
| verify(mLinkBandwidthEstimator).registerCallback( |
| linkBandwidthEstimatorCallbackCaptor.capture()); |
| mLinkBandwidthEstimatorCallback = linkBandwidthEstimatorCallbackCaptor.getValue(); |
| |
| List<DataProfile> profiles = List.of(mGeneralPurposeDataProfile, |
| mGeneralPurposeDataProfileAlternative, mImsCellularDataProfile, |
| mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile, |
| mTetheringDataProfile); |
| |
| doAnswer(invocation -> { |
| DataProfile dp = (DataProfile) invocation.getArguments()[0]; |
| |
| if (dp.getApnSetting() == null) return true; |
| |
| for (DataProfile dataProfile : profiles) { |
| if (dataProfile.getApnSetting() != null |
| && dataProfile.getApnSetting().equals(dp.getApnSetting(), false)) { |
| return true; |
| } |
| } |
| return null; |
| }).when(mDataProfileManager).isDataProfileCompatible(any(DataProfile.class)); |
| |
| doAnswer(invocation -> { |
| DataProfile a = (DataProfile) invocation.getArguments()[0]; |
| DataProfile b = (DataProfile) invocation.getArguments()[1]; |
| return a != null |
| && b != null |
| && a.getApnSetting() != null |
| && a.getApnSetting().equals(b.getApnSetting(), |
| mPhone.getServiceState().getDataRoamingFromRegistration()); |
| }).when(mDataProfileManager).areDataProfilesSharingApn(any(DataProfile.class), |
| any(DataProfile.class)); |
| |
| doAnswer(invocation -> { |
| TelephonyNetworkRequest networkRequest = |
| (TelephonyNetworkRequest) invocation.getArguments()[0]; |
| int networkType = (int) invocation.getArguments()[1]; |
| boolean ignorePermanentFailure = (boolean) invocation.getArguments()[2]; |
| |
| for (DataProfile dataProfile : profiles) { |
| if (dataProfile.canSatisfy(networkRequest.getCapabilities()) |
| && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0 |
| || (dataProfile.getApnSetting().getNetworkTypeBitmask() |
| & ServiceState.getBitmaskForTech(networkType)) != 0) |
| && (ignorePermanentFailure || (dataProfile.getApnSetting() != null |
| && !dataProfile.getApnSetting().getPermanentFailed()))) { |
| return dataProfile; |
| } |
| } |
| logd("Cannot find data profile to satisfy " + networkRequest + ", network type=" |
| + TelephonyManager.getNetworkTypeName(networkType)); |
| return null; |
| }).when(mDataProfileManager).getDataProfileForNetworkRequest( |
| any(TelephonyNetworkRequest.class), anyInt(), anyBoolean()); |
| |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(anyInt()); |
| |
| doAnswer(invocation -> { |
| ((Runnable) invocation.getArguments()[0]).run(); |
| return null; |
| }).when(mMockedDataNetworkControllerCallback).invokeFromExecutor(any(Runnable.class)); |
| doAnswer(invocation -> { |
| ((Runnable) invocation.getArguments()[0]).run(); |
| return null; |
| }).when(mMockedDataRetryManagerCallback).invokeFromExecutor(any(Runnable.class)); |
| |
| mDataNetworkControllerUT.registerDataNetworkControllerCallback( |
| mMockedDataNetworkControllerCallback); |
| |
| mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, |
| 10/*SIM_STATE_LOADED*/, 0).sendToTarget(); |
| mDataNetworkControllerUT.obtainMessage(8/*EVENT_DATA_SERVICE_BINDING_CHANGED*/, |
| new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, true, null)) |
| .sendToTarget(); |
| mDataNetworkControllerUT.obtainMessage(8/*EVENT_DATA_SERVICE_BINDING_CHANGED*/, |
| new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, true, null)) |
| .sendToTarget(); |
| |
| ArgumentCaptor<ImsStateCallback> imsCallbackCaptor = |
| ArgumentCaptor.forClass(ImsStateCallback.class); |
| verify(mMockedImsMmTelManager).registerImsStateCallback(any(Executor.class), |
| imsCallbackCaptor.capture()); |
| mMmtelStateCallback = imsCallbackCaptor.getValue(); |
| |
| verify(mMockedImsRcsManager).registerImsStateCallback(any(Executor.class), |
| imsCallbackCaptor.capture()); |
| mRcsStateCallback = imsCallbackCaptor.getValue(); |
| |
| carrierConfigChanged(); |
| |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| |
| // IMS registration |
| doReturn(FAKE_MMTEL_PACKAGE).when(mMockedImsResolver).getConfiguredImsServicePackageName( |
| anyInt(), eq(ImsFeature.FEATURE_MMTEL)); |
| doReturn(FAKE_RCS_PACKAGE).when(mMockedImsResolver).getConfiguredImsServicePackageName( |
| anyInt(), eq(ImsFeature.FEATURE_RCS)); |
| |
| mMmtelStateCallback.onAvailable(); |
| mRcsStateCallback.onAvailable(); |
| |
| ArgumentCaptor<RegistrationCallback> regCallbackCaptor = |
| ArgumentCaptor.forClass(RegistrationCallback.class); |
| |
| verify(mMockedImsMmTelManager).registerImsRegistrationCallback(any(Executor.class), |
| regCallbackCaptor.capture()); |
| mMmtelRegCallback = regCallbackCaptor.getValue(); |
| |
| verify(mMockedImsRcsManager).registerImsRegistrationCallback(any(Executor.class), |
| regCallbackCaptor.capture()); |
| mRcsRegCallback = regCallbackCaptor.getValue(); |
| |
| processAllMessages(); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| logd("DataNetworkControllerTest -Setup!"); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| logd("tearDown"); |
| mMockedDataServiceManagers.clear(); |
| mDataCallListChangedRegistrants.clear(); |
| mDataNetworkControllerUT = null; |
| mCarrierConfig = null; |
| super.tearDown(); |
| } |
| |
| private @NonNull TelephonyNetworkRequest createNetworkRequest(Integer... capabilities) { |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| for (int networkCapability : capabilities) { |
| netCaps.addCapability(networkCapability); |
| } |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| |
| return new TelephonyNetworkRequest(nativeNetworkRequest, mPhone); |
| } |
| |
| // The purpose of this test is to make sure the network request insertion/removal works as |
| // expected, and make sure it is always sorted. |
| @Test |
| public void testNetworkRequestList() { |
| NetworkRequestList networkRequestList = new NetworkRequestList(); |
| |
| TelephonyNetworkRequest internetNetworkRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| TelephonyNetworkRequest eimsNetworkRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_EIMS); |
| TelephonyNetworkRequest mmsNetworkRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_MMS); |
| networkRequestList.add(internetNetworkRequest); |
| networkRequestList.add(eimsNetworkRequest); |
| networkRequestList.add(mmsNetworkRequest); |
| |
| // Check if emergency has the highest priority, then mms, then internet. |
| assertThat(networkRequestList.get(0).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_EIMS); |
| assertThat(networkRequestList.get(1).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_MMS); |
| assertThat(networkRequestList.get(2).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Add IMS |
| TelephonyNetworkRequest imsNetworkRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_IMS); |
| assertThat(networkRequestList.add(imsNetworkRequest)).isTrue(); |
| |
| assertThat(networkRequestList.get(0).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_EIMS); |
| assertThat(networkRequestList.get(1).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_MMS); |
| assertThat(networkRequestList.get(2).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_IMS); |
| assertThat(networkRequestList.get(3).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Add IMS again |
| assertThat(networkRequestList.add(imsNetworkRequest)).isFalse(); |
| assertThat(networkRequestList.size()).isEqualTo(4); |
| |
| // Remove MMS |
| assertThat(networkRequestList.remove(mmsNetworkRequest)).isTrue(); |
| assertThat(networkRequestList.get(0).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_EIMS); |
| assertThat(networkRequestList.get(1).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_IMS); |
| assertThat(networkRequestList.get(2).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Remove EIMS |
| assertThat(networkRequestList.remove(eimsNetworkRequest)).isTrue(); |
| assertThat(networkRequestList.get(0).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_IMS); |
| assertThat(networkRequestList.get(1).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Remove Internet |
| assertThat(networkRequestList.remove(internetNetworkRequest)).isTrue(); |
| assertThat(networkRequestList.get(0).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| // Remove XCAP (which does not exist) |
| assertThat(networkRequestList.remove( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_XCAP))).isFalse(); |
| assertThat(networkRequestList.get(0).getCapabilities()[0]) |
| .isEqualTo(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| // Remove IMS |
| assertThat(networkRequestList.remove(imsNetworkRequest)).isTrue(); |
| assertThat(networkRequestList).isEmpty(); |
| } |
| |
| private @NonNull List<DataNetwork> getDataNetworks() throws Exception { |
| Field field = DataNetworkController.class.getDeclaredField("mDataNetworkList"); |
| field.setAccessible(true); |
| return (List<DataNetwork>) field.get(mDataNetworkControllerUT); |
| } |
| |
| private void verifyInternetConnected() throws Exception { |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| } |
| |
| private void verifyConnectedNetworkHasCapabilities(@NetCapability int... networkCapabilities) |
| throws Exception { |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| for (DataNetwork dataNetwork : getDataNetworks()) { |
| if (dataNetwork.isConnected() && Arrays.stream(networkCapabilities).boxed() |
| .allMatch(dataNetwork.getNetworkCapabilities()::hasCapability)) { |
| return; |
| } |
| } |
| fail("No network with " + DataUtils.networkCapabilitiesToString(networkCapabilities) |
| + " is connected. dataNetworkList=" + dataNetworkList); |
| } |
| |
| private void verifyNoConnectedNetworkHasCapability(@NetCapability int networkCapability) |
| throws Exception { |
| for (DataNetwork dataNetwork : getDataNetworks()) { |
| assertWithMessage("Network " + dataNetwork + " should not be connected.") |
| .that(dataNetwork.isConnected() && dataNetwork.getNetworkCapabilities() |
| .hasCapability(networkCapability)).isFalse(); |
| } |
| } |
| |
| private void verifyConnectedNetworkHasDataProfile(@NonNull DataProfile dataProfile) |
| throws Exception { |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| for (DataNetwork dataNetwork : getDataNetworks()) { |
| if (dataNetwork.isConnected() && dataNetwork.getDataProfile().equals(dataProfile)) { |
| return; |
| } |
| } |
| fail("No network with " + dataProfile + " is connected. dataNetworkList=" |
| + dataNetworkList); |
| } |
| |
| private void verifyAllDataDisconnected() throws Exception { |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertWithMessage("All data should be disconnected but it's not. " + dataNetworkList) |
| .that(dataNetworkList).isEmpty(); |
| } |
| |
| // To test the basic data setup. Copy this as example for other tests. |
| @Test |
| public void testSetupDataNetwork() throws Exception { |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| DataNetwork dataNetwork = dataNetworkList.get(0); |
| assertThat(dataNetworkList.get(0).getLinkProperties().getAddresses()).containsExactly( |
| InetAddresses.parseNumericAddress(IPV4_ADDRESS), |
| InetAddresses.parseNumericAddress(IPV6_ADDRESS)); |
| |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); |
| } |
| |
| @Test |
| public void testSetupDataNetworkWithSimilarDataProfile() throws Exception { |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| DataNetwork dataNetwork = dataNetworkList.get(0); |
| assertThat(dataNetworkList.get(0).getLinkProperties().getAddresses()).containsExactly( |
| InetAddresses.parseNumericAddress(IPV4_ADDRESS), |
| InetAddresses.parseNumericAddress(IPV6_ADDRESS)); |
| |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); |
| |
| // database updated/reloaded, causing data profile id change |
| List<DataProfile> profiles = List.of(mDuplicatedGeneralPurposeDataProfile); |
| doAnswer(invocation -> { |
| DataProfile dp = (DataProfile) invocation.getArguments()[0]; |
| |
| if (dp.getApnSetting() == null) return true; |
| |
| for (DataProfile dataProfile : profiles) { |
| if (dataProfile.getApnSetting() != null |
| && dataProfile.getApnSetting().equals(dp.getApnSetting(), false)) { |
| return true; |
| } |
| } |
| return null; |
| }).when(mDataProfileManager).isDataProfileCompatible(any(DataProfile.class)); |
| doAnswer(invocation -> { |
| TelephonyNetworkRequest networkRequest = |
| (TelephonyNetworkRequest) invocation.getArguments()[0]; |
| int networkType = (int) invocation.getArguments()[1]; |
| |
| for (DataProfile dataProfile : profiles) { |
| if (dataProfile.canSatisfy(networkRequest.getCapabilities()) |
| && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0 |
| || (dataProfile.getApnSetting().getNetworkTypeBitmask() |
| & ServiceState.getBitmaskForTech(networkType)) != 0)) { |
| return dataProfile; |
| } |
| } |
| logd("Cannot find data profile to satisfy " + networkRequest + ", network type=" |
| + TelephonyManager.getNetworkTypeName(networkType)); |
| return null; |
| }).when(mDataProfileManager).getDataProfileForNetworkRequest( |
| any(TelephonyNetworkRequest.class), anyInt(), anyBoolean()); |
| |
| // verify the network still connects |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); |
| |
| // A NOT_VCN_MANAGED request cannot be satisfied by the existing network, but will adopt the |
| // same data profile |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET, |
| NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); |
| |
| processAllMessages(); |
| |
| // verify the network still connects |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); |
| // verify we don't try to setup a separate network for the not_vcn_managed request |
| dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| } |
| |
| @Test |
| public void testSetupImsDataNetwork() throws Exception { |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| verifyConnectedNetworkHasDataProfile(mImsCellularDataProfile); |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList.get(0).getLinkProperties().getAddresses()).containsExactly( |
| InetAddresses.parseNumericAddress(IPV4_ADDRESS), |
| InetAddresses.parseNumericAddress(IPV6_ADDRESS)); |
| } |
| |
| @Test |
| public void testSetupEnterpriseDataNetwork() throws Exception { |
| List<TrafficDescriptor> tdList = new ArrayList<>(); |
| tdList.add(new TrafficDescriptor.Builder() |
| .setOsAppId(new OsAppId(OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1).getBytes()) |
| .build()); |
| setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, |
| createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); |
| doReturn(mEnterpriseDataProfile).when(mDataProfileManager) |
| .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), |
| anyBoolean()); |
| |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); |
| netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest( |
| new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, |
| NetworkRequest.Type.REQUEST), mPhone)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList.get(0).getLinkProperties().getAddresses()).containsExactly( |
| InetAddresses.parseNumericAddress(IPV4_ADDRESS), |
| InetAddresses.parseNumericAddress(IPV6_ADDRESS)); |
| } |
| |
| @Test |
| public void testDataNetworkControllerCallback() throws Exception { |
| Field field = DataNetworkController.class.getDeclaredField( |
| "mDataNetworkControllerCallbacks"); |
| field.setAccessible(true); |
| Set<DataNetworkControllerCallback> dataNetworkControllerCallbacks = |
| (Set<DataNetworkControllerCallback>) field.get(mDataNetworkControllerUT); |
| |
| // Verify register callback |
| mDataNetworkControllerUT.registerDataNetworkControllerCallback( |
| mMockedDataNetworkControllerCallback); |
| TelephonyNetworkRequest request = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| mDataNetworkControllerUT.addNetworkRequest(request); |
| processAllMessages(); |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(true); |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); |
| |
| int countOfCallbacks = dataNetworkControllerCallbacks.size(); |
| |
| // Verify unregister callback |
| mDataNetworkControllerUT.removeNetworkRequest(request); |
| processAllMessages(); |
| getDataNetworks().get(0).tearDown(DataNetwork |
| .TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED); |
| processAllFutureMessages(); |
| |
| assertEquals(countOfCallbacks - 1, dataNetworkControllerCallbacks.size()); |
| } |
| |
| @Test |
| public void testSimRemovalDataTearDown() throws Exception { |
| testSetupDataNetwork(); |
| |
| mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, |
| TelephonyManager.SIM_STATE_ABSENT, 0).sendToTarget(); |
| processAllMessages(); |
| verifyAllDataDisconnected(); |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(false); |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); |
| verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( |
| eq(DataCallResponse.LINK_STATUS_INACTIVE)); |
| } |
| |
| @Test |
| public void testSimRemovalAndThenInserted() throws Exception { |
| testSimRemovalDataTearDown(); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| // Insert the SIM again. |
| mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, |
| TelephonyManager.SIM_STATE_LOADED, 0).sendToTarget(); |
| processAllMessages(); |
| |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testDuplicateInterface() throws Exception { |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // The fota network request would result in duplicate interface. |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_FOTA)); |
| processAllFutureMessages(); |
| |
| // There should be only one network. |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| assertThat(dataNetworkList.get(0).getDataProfile()).isEqualTo(mGeneralPurposeDataProfile); |
| verifyInternetConnected(); |
| // Fota should not be connected. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); |
| |
| // There should be exactly 2 setup data call requests. |
| verify(mMockedWwanDataServiceManager, times(2)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testMovingFromNoServiceToInService() throws Exception { |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Network becomes in-service. |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testMovingFromInServiceToNoService() throws Exception { |
| testSetupDataNetwork(); |
| |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); |
| // Verify we don't tear down the data network. |
| verifyInternetConnected(); |
| |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UNKNOWN, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); |
| // Verify we don't tear down the data network. |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testPsRestrictedAndLifted() throws Exception { |
| testSetupDataNetwork(); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| // PS restricted, existing PDN should stay. |
| mDataNetworkControllerUT.obtainMessage(6/*EVENT_PS_RESTRICT_ENABLED*/).sendToTarget(); |
| processAllMessages(); |
| |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // PS restricted, new setup NOT allowed |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2); |
| processAllMessages(); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| |
| // PS unrestricted, new setup is allowed |
| mDataNetworkControllerUT.obtainMessage(7/*EVENT_PS_RESTRICT_DISABLED*/).sendToTarget(); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| } |
| |
| @Test |
| public void testPsRestrictedAllowIwlan() throws Exception { |
| // IMS preferred on IWLAN. |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability( |
| eq(NetworkCapabilities.NET_CAPABILITY_IMS)); |
| |
| // PS restricted |
| mDataNetworkControllerUT.obtainMessage(6/*EVENT_PS_RESTRICT_ENABLED*/).sendToTarget(); |
| processAllMessages(); |
| |
| // PS restricted, new setup NOT allowed |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2); |
| processAllMessages(); |
| verifyAllDataDisconnected(); |
| |
| // Request IMS |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN), 3); |
| processAllMessages(); |
| |
| // Make sure IMS on IWLAN. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); |
| assertThat(getDataNetworks()).hasSize(1); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| } |
| |
| @Test |
| public void testRatChanges() throws Exception { |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| |
| testSetupDataNetwork(); |
| |
| // Now RAT changes from LTE to UMTS, make sure the network is lingered. |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| verifyInternetConnected(); |
| |
| // Now RAT changes from UMTS to GSM |
| doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest( |
| any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM), |
| anyBoolean()); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_GSM, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| verifyAllDataDisconnected(); |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(false); |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); |
| verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( |
| eq(DataCallResponse.LINK_STATUS_INACTIVE)); |
| |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| // Now RAT changes from GSM to UMTS |
| doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest( |
| any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS), |
| anyBoolean()); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| doReturn(mGeneralPurposeDataProfile).when(mDataProfileManager) |
| .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), |
| anyBoolean()); |
| // Now RAT changes from UMTS to LTE |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testRatChangesLingeringNotSet() throws Exception { |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| TelephonyNetworkRequest fotaRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_FOTA); |
| mDataNetworkControllerUT.addNetworkRequest(fotaRequest); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_FOTA); |
| |
| // Now RAT changes from LTE to UMTS, since FOTA APN does not have lingering set, only |
| // network type bitmask should be used. Fota network should be torn down. |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| processAllMessages(); |
| |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testVoiceCallEndedOnVoiceDataNonConcurrentNetwork() throws Exception { |
| doReturn(false).when(mSST).isConcurrentVoiceAndDataAllowed(); |
| doReturn(PhoneConstants.State.OFFHOOK).when(mCT).getState(); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Data should not be allowed when voice/data concurrent is not supported. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Call ended. |
| doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); |
| mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); |
| processAllMessages(); |
| |
| // It should have no internet setup at the beginning. |
| verifyAllDataDisconnected(); |
| |
| // But after some delays data should be restored. |
| moveTimeForward(500); |
| processAllMessages(); |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testEcbmChanged() throws Exception { |
| doReturn(true).when(mPhone).isInCdmaEcm(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Data should not be allowed when the device is in ECBM. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Exit ECBM |
| doReturn(false).when(mPhone).isInCdmaEcm(); |
| mDataNetworkControllerUT.obtainMessage(20/*EVENT_EMERGENCY_CALL_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| |
| // Verify data is restored. |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testRoamingDataChanged() throws Exception { |
| doReturn(true).when(mServiceState).getDataRoaming(); |
| |
| // Roaming data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(false); |
| processAllMessages(); |
| |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Data should not be allowed when roaming data is disabled. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| // Roaming data enabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(true); |
| processAllMessages(); |
| |
| // Verify data is restored. |
| verifyInternetConnected(); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| // Roaming data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(false); |
| processAllMessages(); |
| |
| // Verify data is torn down. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Registration is back to HOME. |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| processAllFutureMessages(); |
| |
| // Verify data is restored. |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testDataEnabledChanged() throws Exception { |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Data should not be allowed when user data is disabled. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| // User data enabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, true, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Verify data is restored. |
| verifyInternetConnected(); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Verify data is torn down. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| } |
| |
| @Test |
| public void testNotifyWhenSetDataEnabled() throws Exception { |
| // Set a valid sub id, DEFAULT_SUBSCRIPTION_ID |
| int subId = Integer.MAX_VALUE; |
| Field field = DataSettingsManager.class.getDeclaredField("mSubId"); |
| field.setAccessible(true); |
| field.setInt(mDataNetworkControllerUT.getDataSettingsManager(), subId); |
| boolean isDataEnabled = mDataNetworkControllerUT.getDataSettingsManager().isDataEnabled(); |
| doReturn(mDataNetworkControllerUT.getDataSettingsManager()) |
| .when(mPhone).getDataSettingsManager(); |
| MultiSimSettingController controller = Mockito.spy(new MultiSimSettingController(mContext)); |
| doReturn(true).when(controller).isCarrierConfigLoadedForAllSub(); |
| replaceInstance(MultiSimSettingController.class, "sInstance", null, controller); |
| |
| // Mock Data Overall data is always enabled due to auto data switch, |
| // verify the test shouldn't rely on the overall data status |
| doReturn(1).when(mPhone).getSubId(); |
| doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); |
| Phone phone2 = Mockito.mock(Phone.class); |
| phone2.mCi = mSimulatedCommands; |
| doReturn(true).when(phone2).isUserDataEnabled(); |
| doReturn(mDataSettingsManager).when(phone2).getDataSettingsManager(); |
| replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, phone2}); |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true); |
| processAllMessages(); |
| clearInvocations(mPhone); |
| |
| controller.notifyAllSubscriptionLoaded(); |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, !isDataEnabled, |
| mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Verify not to notify MultiSimSettingController due to internal calling package |
| verify(controller, never()).notifyUserDataEnabled(anyInt(), anyBoolean()); |
| |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, isDataEnabled, |
| mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Verify not to notify MultiSimSettingController due to internal calling package |
| verify(controller, never()).notifyUserDataEnabled(anyInt(), anyBoolean()); |
| |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, !isDataEnabled, "com.android.settings"); |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, isDataEnabled, "com.android.settings"); |
| processAllMessages(); |
| |
| // Verify to notify MultiSimSettingController exactly 2 times |
| verify(controller, times(2)).notifyUserDataEnabled(anyInt(), anyBoolean()); |
| verify(mPhone, never()).notifyDataEnabled(anyBoolean(), anyInt()); |
| } |
| |
| @Test |
| public void testMmsAlwaysAllowedDataDisabled() throws Exception { |
| // Data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| // Always allow MMS |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, true); |
| processAllMessages(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); |
| processAllMessages(); |
| |
| // Make sure MMS is the only capability advertised, but not internet or SUPL. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); |
| |
| mDataNetworkControllerUT.obtainMessage(16 /*EVENT_REEVALUATE_EXISTING_DATA_NETWORKS*/, |
| DataEvaluation.DataEvaluationReason.DATA_SERVICE_STATE_CHANGED).sendToTarget(); |
| |
| processAllFutureMessages(); |
| |
| // Make sure IMS network is not torn down |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| |
| // Remove MMS data enabled override |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, false); |
| processAllMessages(); |
| |
| // Make sure MMS is torn down when the override is disabled. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMS); |
| } |
| |
| @Test |
| public void testMmsAlwaysAllowedRoamingDisabled() throws Exception { |
| // Data roaming disabled |
| doReturn(true).when(mServiceState).getDataRoaming(); |
| mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(false); |
| processAllMessages(); |
| |
| // Device is roaming |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| // Always allow MMS |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, true); |
| processAllMessages(); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); |
| processAllMessages(); |
| |
| // Make sure MMS is not allowed. MMS always allowed should be only applicable to data |
| // disabled case. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMS); |
| } |
| |
| @Test |
| public void testIsDataEnabledOverriddenForApnDataDuringCall() throws Exception { |
| doReturn(1).when(mPhone).getSubId(); |
| doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); |
| // Data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| |
| // Enable during data call mobile policy |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, true); |
| processAllMessages(); |
| |
| // No active phone call |
| doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Verify no internet connection due to no active phone call |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Phone ringing |
| doReturn(PhoneConstants.State.RINGING).when(mPhone).getState(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Verify internet connection |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Disable during data call mobile policy |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, false); |
| processAllMessages(); |
| |
| // Verify no internet connection |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| } |
| |
| @Test |
| public void testIsDataEnabledOverriddenForApnAutoDataSwitch() throws Exception { |
| // Assume phone2 is the default data phone |
| Phone phone2 = Mockito.mock(Phone.class); |
| replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, phone2}); |
| doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); |
| |
| // Data disabled on nonDDS |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| |
| // Enable auto data switch mobile policy |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true); |
| processAllMessages(); |
| |
| // use disabled data on DDS |
| doReturn(false).when(phone2).isUserDataEnabled(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Verify no internet connection |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // use enabled data on DDS |
| doReturn(true).when(phone2).isUserDataEnabled(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Verify internet connection |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Disable auto data switch mobile policy, but enabled data during call |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, false); |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, true); |
| doReturn(PhoneConstants.State.RINGING).when(phone2).getState(); |
| processAllMessages(); |
| |
| // Verify internet connection |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Disable data during call |
| mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager |
| .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, false); |
| processAllMessages(); |
| |
| // Verify no internet connection |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| } |
| |
| @Test |
| public void testUnmeteredRequestPreferredOnIwlan() throws Exception { |
| // Preferred on cellular |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(anyInt()); |
| // Data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Data should not be allowed when roaming + user data are disabled (soft failure reasons) |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| // Set transport to WLAN (unmetered) |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability( |
| eq(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| // Data remain disabled, but trigger the preference evaluation. |
| mDataNetworkControllerUT.obtainMessage(21 /*EVENT_EVALUATE_PREFERRED_TRANSPORT*/, |
| NetworkCapabilities.NET_CAPABILITY_INTERNET, 0).sendToTarget(); |
| mDataNetworkControllerUT.obtainMessage(5 /*EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS*/, |
| DataEvaluation.DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED).sendToTarget(); |
| processAllMessages(); |
| |
| // Verify data is allowed even if data is disabled. |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testUnmeteredRequestDataRoamingDisabled() throws Exception { |
| // Data roaming disabled |
| doReturn(true).when(mServiceState).getDataRoaming(); |
| mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(false); |
| processAllMessages(); |
| |
| // MMS is unmetered |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, |
| new String[]{"default", "dun", "supl"}); |
| carrierConfigChanged(); |
| // Manually set data roaming to false in case ro.com.android.dataroaming is true. |
| // TODO(b/232575718): Figure out a way to mock ro.com.android.dataroaming for tests. |
| mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(false); |
| // Device is roaming |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| } |
| |
| @Test |
| public void testUnmeteredRequestDataDisabled() throws Exception { |
| // MMS is unmetered |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, |
| new String[]{"default", "dun", "supl"}); |
| carrierConfigChanged(); |
| |
| // Data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); |
| |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| } |
| |
| @Test |
| public void testEmergencyRequest() throws Exception { |
| // Data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_EIMS)); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_EIMS); |
| verifyConnectedNetworkHasDataProfile(mEmergencyDataProfile); |
| } |
| |
| @Test |
| public void testHandoverRuleFromString() { |
| HandoverRule handoverRule = new HandoverRule("source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, " |
| + "target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"); |
| assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.GERAN, |
| AccessNetworkType.UTRAN, AccessNetworkType.EUTRAN, AccessNetworkType.NGRAN, |
| AccessNetworkType.IWLAN); |
| assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.GERAN, |
| AccessNetworkType.UTRAN, AccessNetworkType.EUTRAN, AccessNetworkType.NGRAN, |
| AccessNetworkType.IWLAN); |
| assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_ALLOWED); |
| assertThat(handoverRule.isOnlyForRoaming).isFalse(); |
| assertThat(handoverRule.networkCapabilities).isEmpty(); |
| |
| handoverRule = new HandoverRule("source= NGRAN| IWLAN, " |
| + "target = EUTRAN, type = disallowed "); |
| assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.NGRAN, |
| AccessNetworkType.IWLAN); |
| assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); |
| assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); |
| assertThat(handoverRule.isOnlyForRoaming).isFalse(); |
| assertThat(handoverRule.networkCapabilities).isEmpty(); |
| |
| handoverRule = new HandoverRule("source= IWLAN, " |
| + "target = EUTRAN, type = disallowed, roaming = true," |
| + " capabilities = IMS | EIMS "); |
| assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.IWLAN); |
| assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN); |
| assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); |
| assertThat(handoverRule.networkCapabilities).containsExactly( |
| NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_EIMS); |
| assertThat(handoverRule.isOnlyForRoaming).isTrue(); |
| |
| handoverRule = new HandoverRule("source=EUTRAN|NGRAN|IWLAN|UNKNOWN, " |
| + "target=EUTRAN|NGRAN|IWLAN, type=disallowed, capabilities = IMS|EIMS"); |
| assertThat(handoverRule.sourceAccessNetworks).containsExactly(AccessNetworkType.EUTRAN, |
| AccessNetworkType.NGRAN, AccessNetworkType.IWLAN, AccessNetworkType.UNKNOWN); |
| assertThat(handoverRule.targetAccessNetworks).containsExactly(AccessNetworkType.EUTRAN, |
| AccessNetworkType.NGRAN, AccessNetworkType.IWLAN); |
| assertThat(handoverRule.type).isEqualTo(HandoverRule.RULE_TYPE_DISALLOWED); |
| assertThat(handoverRule.networkCapabilities).containsExactly( |
| NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_EIMS); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("V2hhdCBUaGUgRnVjayBpcyB0aGlzIQ==")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=GERAN, target=UNKNOWN, type=disallowed, " |
| + "capabilities=IMS")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=UNKNOWN, target=IWLAN, type=allowed, " |
| + "capabilities=IMS")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=GERAN, target=IWLAN, type=wtf")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=GERAN, target=NGRAN, type=allowed")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=IWLAN, target=WTFRAN, type=allowed")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=IWLAN, target=|, type=allowed")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, capabilities=|")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, capabilities=")); |
| |
| assertThrows(IllegalArgumentException.class, |
| () -> new HandoverRule("source=GERAN, target=IWLAN, type=allowed, " |
| + "capabilities=wtf")); |
| } |
| |
| @Test |
| public void testIsNetworkTypeCongested() throws Exception { |
| Set<Integer> congestedNetworkTypes = new ArraySet<>(); |
| doReturn(congestedNetworkTypes).when(mDataNetworkController) |
| .getCongestedOverrideNetworkTypes(); |
| testSetupDataNetwork(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| |
| // Set 5G unmetered |
| congestedNetworkTypes.add(TelephonyManager.NETWORK_TYPE_NR); |
| mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, |
| NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED, |
| NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED, |
| new int[]{TelephonyManager.NETWORK_TYPE_NR}).sendToTarget(); |
| dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); |
| processAllMessages(); |
| assertEquals(congestedNetworkTypes, |
| mDataNetworkControllerUT.getCongestedOverrideNetworkTypes()); |
| assertTrue(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)); |
| |
| // Change data network type to NR |
| doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_NR, |
| TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false)) |
| .when(mDisplayInfoController).getTelephonyDisplayInfo(); |
| dataNetwork.sendMessage(13/*EVENT_DISPLAY_INFO_CHANGED*/); |
| processAllMessages(); |
| assertFalse(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)); |
| |
| // Set all network types metered |
| congestedNetworkTypes.clear(); |
| mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, |
| NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED, 0, |
| TelephonyManager.getAllNetworkTypes()).sendToTarget(); |
| dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); |
| processAllMessages(); |
| assertTrue(mDataNetworkControllerUT.getCongestedOverrideNetworkTypes().isEmpty()); |
| assertTrue(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)); |
| } |
| |
| @Test |
| public void testIsNetworkTypeUnmeteredViaSubscriptionOverride() throws Exception { |
| Set<Integer> unmeteredNetworkTypes = new ArraySet<>(); |
| doReturn(unmeteredNetworkTypes).when(mDataNetworkController) |
| .getUnmeteredOverrideNetworkTypes(); |
| testSetupDataNetwork(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| |
| // Set 5G unmetered |
| unmeteredNetworkTypes.add(TelephonyManager.NETWORK_TYPE_NR); |
| mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, |
| NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED, |
| NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED, |
| new int[]{TelephonyManager.NETWORK_TYPE_NR}).sendToTarget(); |
| dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); |
| processAllMessages(); |
| assertEquals(unmeteredNetworkTypes, |
| mDataNetworkControllerUT.getUnmeteredOverrideNetworkTypes()); |
| assertFalse(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); |
| assertThat(mDataNetworkControllerUT.isInternetUnmetered()).isFalse(); |
| |
| // Change data network type to NR |
| doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_NR, |
| TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false)) |
| .when(mDisplayInfoController).getTelephonyDisplayInfo(); |
| dataNetwork.sendMessage(13/*EVENT_DISPLAY_INFO_CHANGED*/); |
| processAllMessages(); |
| assertTrue(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); |
| assertThat(mDataNetworkControllerUT.isInternetUnmetered()).isTrue(); |
| |
| // Set all network types metered |
| unmeteredNetworkTypes.clear(); |
| mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, |
| NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED, 0, |
| TelephonyManager.getAllNetworkTypes()).sendToTarget(); |
| dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); |
| processAllMessages(); |
| assertTrue(mDataNetworkControllerUT.getUnmeteredOverrideNetworkTypes().isEmpty()); |
| assertFalse(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); |
| assertThat(mDataNetworkControllerUT.isInternetUnmetered()).isFalse(); |
| } |
| |
| @Test |
| public void testIsNetworkTypeUnmeteredViaSubscriptionPlans() throws Exception { |
| List<SubscriptionPlan> subscriptionPlans = new ArrayList<>(); |
| doReturn(subscriptionPlans).when(mDataNetworkController).getSubscriptionPlans(); |
| testSetupDataNetwork(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| |
| // Set 5G unmetered |
| SubscriptionPlan unmetered5GPlan = SubscriptionPlan.Builder |
| .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), |
| Period.ofMonths(1)) |
| .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED, |
| SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) |
| .setNetworkTypes(new int[]{TelephonyManager.NETWORK_TYPE_NR}) |
| .build(); |
| SubscriptionPlan generalMeteredPlan = SubscriptionPlan.Builder |
| .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), |
| Period.ofMonths(1)) |
| .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) |
| .setDataUsage(500_000_000, System.currentTimeMillis()) |
| .build(); |
| subscriptionPlans.add(generalMeteredPlan); |
| subscriptionPlans.add(unmetered5GPlan); |
| mDataNetworkControllerUT.obtainMessage(22/*EVENT_SUBSCRIPTION_PLANS_CHANGED*/, |
| new SubscriptionPlan[]{generalMeteredPlan, unmetered5GPlan}).sendToTarget(); |
| dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); |
| processAllMessages(); |
| assertEquals(subscriptionPlans, mDataNetworkControllerUT.getSubscriptionPlans()); |
| assertFalse(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); |
| assertThat(mDataNetworkControllerUT.isInternetUnmetered()).isFalse(); |
| |
| |
| // Change data network type to NR |
| doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_NR, |
| TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false)) |
| .when(mDisplayInfoController).getTelephonyDisplayInfo(); |
| dataNetwork.sendMessage(13/*EVENT_DISPLAY_INFO_CHANGED*/); |
| processAllMessages(); |
| assertTrue(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); |
| assertThat(mDataNetworkControllerUT.isInternetUnmetered()).isTrue(); |
| |
| // Set all network types metered |
| subscriptionPlans.clear(); |
| mDataNetworkControllerUT.obtainMessage(22/*EVENT_SUBSCRIPTION_PLANS_CHANGED*/, |
| new SubscriptionPlan[]{}).sendToTarget(); |
| dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); |
| processAllMessages(); |
| assertTrue(mDataNetworkControllerUT.getSubscriptionPlans().isEmpty()); |
| assertFalse(dataNetwork.getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); |
| assertThat(mDataNetworkControllerUT.isInternetUnmetered()).isFalse(); |
| } |
| |
| @Test |
| public void testOnSinglePdnArbitrationExemptIms() throws Exception { |
| // On CDMA network, only one data network is allowed. |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_1xRTT, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| // Preferred on cellular |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(anyInt()); |
| // Add IMS |
| TelephonyNetworkRequest ims = createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| mDataNetworkControllerUT.addNetworkRequest(ims); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Add internet, should be compatible |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Both internet and IMS should be retained after network re-evaluation |
| mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) |
| .sendToTarget(); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Add MMS, whose priority > internet, internet should be town down, IMS left untouched |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 3); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Both internet and IMS should be retained after network re-evaluation |
| mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) |
| .sendToTarget(); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Temporarily remove IMS |
| mDataNetworkControllerUT.removeNetworkRequest(ims); |
| processAllMessages(); |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| dataNetworks.get(0).tearDown(DataNetwork.TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED); |
| processAllMessages(); |
| |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| // Add IMS, should be compatible with the existing internet |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 4); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testLinkStatusChanged() throws Exception { |
| testSetupDataNetwork(); |
| verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( |
| eq(DataCallResponse.LINK_STATUS_ACTIVE)); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| |
| DataCallResponse response = createDataCallResponse(1, DataCallResponse.LINK_STATUS_DORMANT); |
| dataNetwork.obtainMessage(8 /*EVENT_DATA_STATE_CHANGED */, |
| new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, |
| List.of(response), null)).sendToTarget(); |
| |
| processAllMessages(); |
| verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( |
| eq(DataCallResponse.LINK_STATUS_DORMANT)); |
| assertThat(mDataNetworkControllerUT.getDataActivity()).isEqualTo( |
| TelephonyManager.DATA_ACTIVITY_DORMANT); |
| } |
| |
| @Test |
| public void testHandoverDataNetwork() throws Exception { |
| testSetupImsDataNetwork(); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| // Before handover the data profile is the cellular IMS data profile |
| verifyConnectedNetworkHasDataProfile(mImsCellularDataProfile); |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(true); |
| |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Verify that IWLAN handover succeeded. |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // After handover the data profile is the IWLAN IMS data profile |
| verifyConnectedNetworkHasDataProfile(mImsIwlanDataProfile); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkBackToBackPreferenceChanged() throws Exception { |
| testSetupImsDataNetwork(); |
| |
| Mockito.reset(mMockedWlanDataServiceManager); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Capture the message for setup data call response. We want to delay it. |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| messageCaptor.capture()); |
| |
| // Before setup data call response, change the preference back to cellular. |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Before setup data call response, change the preference back to IWLAN. |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Finally handover is completed. |
| Message msg = messageCaptor.getValue(); |
| DataCallResponse response = new DataCallResponse.Builder() |
| .setCause(DataFailCause.NONE) |
| .build(); |
| msg.getData().putParcelable("data_call_response", response); |
| msg.arg1 = DataServiceCallback.RESULT_SUCCESS; |
| msg.sendToTarget(); |
| processAllMessages(); |
| |
| // Make sure handover request is only sent once. |
| verify(mMockedWlanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), messageCaptor.capture()); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkBackToBackPreferenceChangedHandoverFail() throws Exception { |
| testSetupImsDataNetwork(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| |
| Mockito.reset(mMockedWlanDataServiceManager); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Capture the message for setup data call response. We want to delay it. |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| messageCaptor.capture()); |
| |
| // Before WLAN setup data call response, change the preference back to cellular. |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Finally WLAN handover is completed with failure. |
| Message msg = messageCaptor.getValue(); |
| DataCallResponse response = new DataCallResponse.Builder() |
| .setCause(DataFailCause.ERROR_UNSPECIFIED) |
| .setRetryDurationMillis(123) |
| .setHandoverFailureMode( |
| DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL) |
| .build(); |
| msg.getData().putParcelable("data_call_response", response); |
| msg.arg1 = DataServiceCallback.RESULT_ERROR_UNSUPPORTED; |
| msg.sendToTarget(); |
| processAllMessages(); |
| |
| // Make sure handover request is only sent once. |
| verify(mMockedWlanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), messageCaptor.capture()); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); |
| assertSame(dataNetwork, getDataNetworks().get(0)); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception { |
| mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, |
| new String[]{"source=EUTRAN, target=IWLAN, type=disallowed, capabilities=MMS|IMS", |
| "source=IWLAN, target=EUTRAN, type=disallowed, capabilities=MMS"}); |
| // Force data config manager to reload the carrier config. |
| mDataNetworkControllerUT.getDataConfigManager().obtainMessage( |
| 1/*EVENT_CARRIER_CONFIG_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| |
| testSetupImsDataNetwork(); |
| |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| // After this, IMS data network should be disconnected, and DNC should attempt to |
| // establish a new one on IWLAN |
| |
| // Verify all modem data disconnected. |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(false); |
| |
| // A new data network should be connected on IWLAN |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| assertThat(dataNetworkList.get(0).isConnected()).isTrue(); |
| assertThat(dataNetworkList.get(0).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue(); |
| assertThat(dataNetworkList.get(0).getTransport()) |
| .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // test IWLAN -> EUTRAN no need to tear down because the disallowed rule only applies to MMS |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| mDataNetworkControllerUT.obtainMessage(21/*EVENT_PREFERRED_TRANSPORT_CHANGED*/, |
| NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget(); |
| Mockito.clearInvocations(mMockedWwanDataServiceManager); |
| processAllMessages(); |
| // Verify that IWWAN handover succeeded. |
| assertThat(getDataNetworks().get(0).getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall( |
| anyInt(), any(), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_HANDOVER), any(), anyInt(), any(), any(), eq(true), |
| any()); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkNotAllowedByRoamingPolicy() throws Exception { |
| mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, |
| new String[]{"source=EUTRAN|NGRAN|IWLAN, target=EUTRAN|NGRAN|IWLAN, roaming=true, " |
| + "type=disallowed, capabilities=IMS"}); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| // Force data config manager to reload the carrier config. |
| mDataNetworkControllerUT.getDataConfigManager().obtainMessage( |
| 1/*EVENT_CARRIER_CONFIG_CHANGED*/).sendToTarget(); |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| processAllMessages(); |
| |
| // Bring up IMS PDN on IWLAN |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); |
| processAllMessages(); |
| verifyConnectedNetworkHasDataProfile(mImsIwlanDataProfile); |
| |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Verify IMS PDN is connected. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // After this, IMS data network should be disconnected, and DNC should attempt to |
| // establish a new one on cellular |
| processAllMessages(); |
| |
| // Verify all data disconnected. |
| verify(mMockedWlanDataServiceManager).deactivateDataCall(anyInt(), anyInt(), any()); |
| |
| // Should setup a new one instead of handover. |
| verify(mMockedWwanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| |
| // A new data network should be connected on IWLAN |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| assertThat(dataNetworkList.get(0).isConnected()).isTrue(); |
| assertThat(dataNetworkList.get(0).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue(); |
| assertThat(dataNetworkList.get(0).getTransport()) |
| .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkRetry() throws Exception { |
| testSetupImsDataNetwork(); |
| |
| setFailedSetupDataResponse(mMockedWlanDataServiceManager, |
| DataFailCause.HANDOVER_FAILED, -1, true); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| // Verify that data network is still on cellular |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Set target transport OOS |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UNKNOWN, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, /* data */ |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, /* voice */ |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, /* iwlan */ |
| null); |
| setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 1); |
| |
| processAllFutureMessages(); |
| // Verify that data network is still on cellular |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Set target transport back to service |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UNKNOWN, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, /* data */ |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, /* voice */ |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, /* iwlan */ |
| null); |
| processAllFutureMessages(); |
| |
| dataNetwork = getDataNetworks().get(0); |
| // Verify that data network is handovered to IWLAN |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkDuplicateRetry() throws Exception { |
| testSetupImsDataNetwork(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .when(mAccessNetworksManager).getPreferredTransportByNetworkCapability(anyInt()); |
| |
| DataRetryManager.DataHandoverRetryEntry retry1 = |
| new DataRetryManager.DataHandoverRetryEntry.Builder<>() |
| .setDataNetwork(dataNetwork) |
| .build(); |
| DataRetryManager.DataHandoverRetryEntry retry2 = |
| new DataRetryManager.DataHandoverRetryEntry.Builder<>() |
| .setDataNetwork(dataNetwork) |
| .build(); |
| final Message msg1 = new Message(); |
| msg1.what = 4 /*EVENT_DATA_HANDOVER_RETRY*/; |
| msg1.obj = retry1; |
| |
| final Message msg2 = new Message(); |
| msg2.what = 4 /*EVENT_DATA_HANDOVER_RETRY*/; |
| msg2.obj = retry2; |
| |
| Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries"); |
| field.setAccessible(true); |
| List<DataRetryManager.DataRetryEntry> dataRetryEntries = |
| (List<DataRetryManager.DataRetryEntry>) |
| field.get(mDataNetworkControllerUT.getDataRetryManager()); |
| dataRetryEntries.add(retry1); |
| dataRetryEntries.add(retry2); |
| |
| mDataNetworkControllerUT.getDataRetryManager().sendMessageDelayed(msg1, 0); |
| mDataNetworkControllerUT.getDataRetryManager().sendMessageDelayed(msg2, 0); |
| |
| processAllFutureMessages(); |
| |
| setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 1); |
| processAllMessages(); |
| |
| dataNetwork = getDataNetworks().get(0); |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), eq(DataService.REQUEST_REASON_HANDOVER), any(), |
| anyInt(), any(), any(), anyBoolean(), any(Message.class)); |
| assertThat(mDataNetworkControllerUT.getDataRetryManager() |
| .isAnyHandoverRetryScheduled(dataNetwork)).isFalse(); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkRetryReachedMaximum() throws Exception { |
| testSetupImsDataNetwork(); |
| |
| // 1. Normal case |
| setFailedSetupDataResponse(mMockedWlanDataServiceManager, |
| DataFailCause.HANDOVER_FAILED, -1, true); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| processAllFutureMessages(); |
| |
| // Should retried 5 times, which is the maximum based on the retry config rules. |
| verify(mMockedWlanDataServiceManager, times(6)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_HANDOVER), any(), anyInt(), any(), any(), |
| anyBoolean(), any(Message.class)); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| // Verify that data network is finally setup on IWLAN. |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| // 2. Active VoPS call, should delay tear down |
| doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); |
| mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, |
| true); |
| carrierConfigChanged(); |
| |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, |
| DataFailCause.HANDOVER_FAILED, -1, true); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| processAllFutureMessages(); |
| |
| // Verify the network wasn't torn down |
| verify(mMockedWlanDataServiceManager, never()).deactivateDataCall(anyInt(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); |
| |
| // Verify tear down after call ends |
| doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); |
| mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); |
| processAllFutureMessages(); |
| |
| verify(mMockedWlanDataServiceManager).deactivateDataCall(anyInt(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkRetryReachedMaximumNetworkRequestRemoved() throws Exception { |
| TelephonyNetworkRequest networkRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_IMS); |
| mDataNetworkControllerUT.addNetworkRequest(networkRequest); |
| processAllMessages(); |
| |
| setFailedSetupDataResponse(mMockedWlanDataServiceManager, |
| DataFailCause.HANDOVER_FAILED, -1, true); |
| mDataNetworkControllerUT.removeNetworkRequest(networkRequest); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| processAllMessages(); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| // Verify that data network should remain on cellular. |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // There shouldn't be any attempt to retry handover on IWLAN. |
| verify(mMockedWlanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_HANDOVER), any(), anyInt(), any(), any(), |
| anyBoolean(), any(Message.class)); |
| |
| // There shouldn't be any attempt to bring up a new one on IWLAN as well. |
| verify(mMockedWlanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), |
| anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkRetryReachedMaximumDelayImsTearDown() throws Exception { |
| // Voice call is ongoing |
| doReturn(PhoneConstants.State.OFFHOOK).when(mCT).getState(); |
| mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, |
| true); |
| carrierConfigChanged(); |
| |
| testSetupImsDataNetwork(); |
| |
| setFailedSetupDataResponse(mMockedWlanDataServiceManager, |
| DataFailCause.HANDOVER_FAILED, -1, true); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| processAllFutureMessages(); |
| |
| // Should retried 5 times, which is the maximum based on the retry config rules. |
| verify(mMockedWlanDataServiceManager, times(6)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_HANDOVER), any(), anyInt(), any(), any(), |
| anyBoolean(), any(Message.class)); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| // Verify that data network is still on WWAN because voice call is still ongoing. |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| } |
| |
| // Test the device enters from 4G to 3G, and QNS switches the pref just before that happens. |
| // Make sure we don't tear down the network and let it handover to IWLAN successfully. |
| @Test |
| public void testHandoverDataNetworkWhileSwitchTo3G() throws Exception { |
| testSetupImsDataNetwork(); |
| |
| // Before handover the data profile is the cellular IMS data profile |
| verifyConnectedNetworkHasDataProfile(mImsCellularDataProfile); |
| |
| // Long delay handover |
| setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 1, 3000); |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| mAccessNetworksManagerCallback.onPreferredTransportChanged( |
| NetworkCapabilities.NET_CAPABILITY_IMS); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| processAllMessages(); |
| |
| // Move the time a little bit, handover still not responded. |
| moveTimeForward(500); |
| processAllMessages(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| // Verify the network is still on cellular, waiting for handover, although already on 3G. |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Now handover should complete. |
| moveTimeForward(5000); |
| processAllMessages(); |
| |
| dataNetwork = getDataNetworks().get(0); |
| // Verify that IWLAN handover succeeded. |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // After handover the data profile is the IWLAN IMS data profile |
| verifyConnectedNetworkHasDataProfile(mImsIwlanDataProfile); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkFailedNullResponse() throws Exception { |
| testSetupImsDataNetwork(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| |
| // Set failed null response |
| doAnswer(invocation -> { |
| final Message msg = (Message) invocation.getArguments()[10]; |
| msg.getData().putParcelable("data_call_response", null); |
| msg.arg1 = DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE; |
| msg.getTarget().sendMessageDelayed(msg, 0); |
| return null; |
| }).when(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), eq(DataService.REQUEST_REASON_HANDOVER), any(), |
| anyInt(), any(), any(), anyBoolean(), any(Message.class)); |
| |
| // Attempt handover |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| processAllMessages(); |
| |
| // Verify that data network is still on cellular and data network was not torn down |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| assertThat(dataNetwork.isConnected()).isTrue(); |
| |
| // Process all handover retries and failures |
| processAllFutureMessages(); |
| |
| // Verify that original data network was torn down and new connection set up on cellular |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| assertThat(dataNetwork.isConnected()).isFalse(); |
| dataNetwork = getDataNetworks().get(0); |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| assertThat(dataNetwork.isConnected()).isTrue(); |
| } |
| |
| @Test |
| public void testSetupDataNetworkRetrySuggestedByNetwork() { |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.CONGESTION, |
| DataCallResponse.RETRY_DURATION_UNDEFINED, false); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllFutureMessages(); |
| |
| // The first 8 retries are short timers that scheduled by handler, future retries are |
| // scheduled by intent and require more complex mock, so we only verify the first 8 here. |
| verify(mMockedWwanDataServiceManager, times(9)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testSetupDataNetworkRetryFailed() { |
| mDataNetworkControllerUT.getDataRetryManager() |
| .registerCallback(mMockedDataRetryManagerCallback); |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.CONGESTION, |
| DataCallResponse.RETRY_DURATION_UNDEFINED, false); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| // Process first retry |
| moveTimeForward(2500); |
| processAllMessages(); |
| verify(mMockedWwanDataServiceManager, times(2)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| ArgumentCaptor<DataRetryManager.DataSetupRetryEntry> retryEntry = |
| ArgumentCaptor.forClass(DataRetryManager.DataSetupRetryEntry.class); |
| verify(mMockedDataRetryManagerCallback, times(1)) |
| .onDataNetworkSetupRetry(retryEntry.capture()); |
| assertThat(retryEntry.getValue().getState()).isEqualTo( |
| DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED); |
| |
| // Cause data network setup failed due to RADIO_DISABLED_BY_CARRIER |
| doReturn(false).when(mSST).getPowerStateFromCarrier(); |
| |
| // Process second retry and ensure data network setup failed |
| moveTimeForward(3000); |
| processAllMessages(); |
| verify(mMockedWwanDataServiceManager, times(2)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| verify(mMockedDataRetryManagerCallback, times(2)) |
| .onDataNetworkSetupRetry(retryEntry.capture()); |
| assertThat(retryEntry.getValue().getState()).isEqualTo( |
| DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED); |
| |
| // Data network setup allowed again |
| doReturn(true).when(mSST).getPowerStateFromCarrier(); |
| |
| // Should not retry again after retry failure |
| processAllFutureMessages(); |
| verify(mMockedWwanDataServiceManager, times(2)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testSetupDataNetworkRetryFailedNetworkRequestRemoved() { |
| mDataNetworkControllerUT.getDataRetryManager() |
| .registerCallback(mMockedDataRetryManagerCallback); |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.CONGESTION, |
| DataCallResponse.RETRY_DURATION_UNDEFINED, false); |
| TelephonyNetworkRequest tnr = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| mDataNetworkControllerUT.addNetworkRequest(tnr); |
| |
| processAllMessages(); |
| |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| Mockito.clearInvocations(mMockedWwanDataServiceManager); |
| |
| logd("Remove internet network request"); |
| mDataNetworkControllerUT.removeNetworkRequest(tnr); |
| |
| moveTimeForward(2500); |
| processAllMessages(); |
| |
| // There should be no retry since request has been removed. |
| verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| Mockito.clearInvocations(mMockedWwanDataServiceManager); |
| |
| // Now send another IMS request |
| tnr = createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS); |
| mDataNetworkControllerUT.addNetworkRequest(tnr); |
| processAllMessages(); |
| |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| Mockito.clearInvocations(mMockedWwanDataServiceManager); |
| |
| logd("Remove IMS network request"); |
| mDataNetworkControllerUT.removeNetworkRequest(tnr); |
| |
| // There should be no retry since request has been removed. |
| verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testSetupDataNetworkRetryFailedNetworkRequestRemovedAndAdded() throws Exception { |
| mDataNetworkControllerUT.getDataRetryManager() |
| .registerCallback(mMockedDataRetryManagerCallback); |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.CONGESTION, |
| 10000, false); |
| |
| TelephonyNetworkRequest firstTnr = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_IMS); |
| TelephonyNetworkRequest secondTnr = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| mDataNetworkControllerUT.addNetworkRequest(firstTnr); |
| processAllMessages(); |
| |
| mDataNetworkControllerUT.removeNetworkRequest(firstTnr); |
| mDataNetworkControllerUT.addNetworkRequest(secondTnr); |
| processAllFutureMessages(); |
| |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| ArgumentCaptor<DataRetryManager.DataSetupRetryEntry> retryEntry = |
| ArgumentCaptor.forClass(DataRetryManager.DataSetupRetryEntry.class); |
| verify(mMockedDataRetryManagerCallback, times(1)) |
| .onDataNetworkSetupRetry(retryEntry.capture()); |
| assertThat(retryEntry.getValue().getState()).isEqualTo( |
| DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED); |
| assertThat(retryEntry.getValue().networkRequestList.size()).isEqualTo(1); |
| assertThat(retryEntry.getValue().networkRequestList.get(0)).isEqualTo(firstTnr); |
| |
| DataRetryManager.DataSetupRetryEntry dataSetupRetryEntry = retryEntry.getValue(); |
| logd("DataSetupRetryEntry:" + dataSetupRetryEntry); |
| |
| processAllMessages(); |
| processAllFutureMessages(); |
| |
| setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 1); |
| logd("Sending TAC_CHANGED event"); |
| mDataNetworkControllerUT.obtainMessage(25/*EVENT_TAC_CHANGED*/).sendToTarget(); |
| mDataNetworkControllerUT.getDataRetryManager().obtainMessage(10/*EVENT_TAC_CHANGED*/) |
| .sendToTarget(); |
| processAllFutureMessages(); |
| |
| // TAC changes should clear the already-scheduled retry and throttling. |
| assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled( |
| mImsCellularDataProfile, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).isFalse(); |
| |
| // But DNC should re-evaluate unsatisfied request and setup IMS again. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| verify(mMockedWwanDataServiceManager, times(2)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testSetupDataNetworkPermanentFailure() { |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.PROTOCOL_ERRORS, |
| DataCallResponse.RETRY_DURATION_UNDEFINED, false); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllFutureMessages(); |
| |
| // There should be only one attempt, and no retry should happen because it's a permanent |
| // failure. |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| eq(mGeneralPurposeDataProfile), anyBoolean(), anyBoolean(), anyInt(), any(), |
| anyInt(), any(), any(), anyBoolean(), any(Message.class)); |
| |
| Mockito.clearInvocations(mMockedWwanDataServiceManager); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllFutureMessages(); |
| |
| // Even receiving a new network request, setup data call should not be sent. |
| verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| // APN should be marked as permanent failure. |
| assertThat(mGeneralPurposeDataProfile.getApnSetting().getPermanentFailed()).isTrue(); |
| } |
| |
| @Test |
| public void testSetupDataNetworkConditionChangesAfterPermanentFailure() throws Exception { |
| testSetupDataNetworkPermanentFailure(); |
| |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 1); |
| |
| // From LTE to NR |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_NR, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| |
| // condition change should trigger setup data, even though previously the APN has been |
| // marked as permanent failure. |
| verifyInternetConnected(); |
| } |
| |
| @Test |
| public void testSetupDataNetworkNetworkSuggestedNeverRetry() { |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.PROTOCOL_ERRORS, |
| Long.MAX_VALUE, false); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllFutureMessages(); |
| |
| // There should be only one attempt, and no retry should happen because it's a permanent |
| // failure. |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testSetupDataNetworkNetworkSuggestedRetryTimerDataThrottled() { |
| mDataNetworkControllerUT.getDataRetryManager() |
| .registerCallback(mMockedDataRetryManagerCallback); |
| |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.PROTOCOL_ERRORS, |
| 10000, false); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); |
| processAllMessages(); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); |
| processAllMessages(); |
| |
| // There should be only one attempt, and no retry should happen because the second one |
| // was throttled. |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| ArgumentCaptor<List<ThrottleStatus>> throttleStatusCaptor = |
| ArgumentCaptor.forClass(List.class); |
| verify(mMockedDataRetryManagerCallback) |
| .onThrottleStatusChanged(throttleStatusCaptor.capture()); |
| assertThat(throttleStatusCaptor.getValue()).hasSize(1); |
| ThrottleStatus throttleStatus = throttleStatusCaptor.getValue().get(0); |
| assertThat(throttleStatus.getApnType()).isEqualTo(ApnSetting.TYPE_IMS); |
| assertThat(throttleStatus.getRetryType()) |
| .isEqualTo(ThrottleStatus.RETRY_TYPE_NEW_CONNECTION); |
| assertThat(throttleStatus.getTransportType()) |
| .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkNetworkSuggestedRetryTimerDataThrottled() throws Exception { |
| testSetupImsDataNetwork(); |
| |
| DataNetwork network = getDataNetworks().get(0); |
| setFailedSetupDataResponse(mMockedWlanDataServiceManager, |
| DataFailCause.HANDOVER_FAILED, 10000, true); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Verify retry scheduled on this network |
| assertThat(mDataNetworkControllerUT.getDataRetryManager() |
| .isAnyHandoverRetryScheduled(network)).isTrue(); |
| // Verify the data profile is throttled on WLAN |
| assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled( |
| network.getDataProfile(), AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).isTrue(); |
| |
| // Test even if network disconnected, the throttle status should remain |
| network.tearDown(DataNetwork.TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED); |
| processAllFutureMessages(); |
| |
| // Verify retry is cleared on this network |
| assertThat(mDataNetworkControllerUT.getDataRetryManager() |
| .isAnyHandoverRetryScheduled(network)).isFalse(); |
| // Verify the data profile is still throttled |
| assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled( |
| network.getDataProfile(), AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).isTrue(); |
| } |
| |
| @Test |
| public void testTacChangesClearThrottlingAndRetryHappens() throws Exception { |
| testSetupDataNetworkNetworkSuggestedRetryTimerDataThrottled(); |
| processAllFutureMessages(); |
| |
| setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 1); |
| logd("Sending TAC_CHANGED event"); |
| mDataNetworkControllerUT.obtainMessage(25/*EVENT_TAC_CHANGED*/).sendToTarget(); |
| mDataNetworkControllerUT.getDataRetryManager().obtainMessage(10/*EVENT_TAC_CHANGED*/) |
| .sendToTarget(); |
| processAllFutureMessages(); |
| |
| // TAC changes should clear the already-scheduled retry and throttling. |
| assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled( |
| mImsCellularDataProfile, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).isFalse(); |
| |
| // But DNC should re-evaluate unsatisfied request and setup IMS again. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testNrAdvancedByPco() throws Exception { |
| testSetupDataNetwork(); |
| verify(mMockedDataNetworkControllerCallback, never()) |
| .onNrAdvancedCapableByPcoChanged(anyBoolean()); |
| mSimulatedCommands.triggerPcoData(1, "IPV6", 1234, new byte[]{1}); |
| processAllMessages(); |
| verify(mMockedDataNetworkControllerCallback).onNrAdvancedCapableByPcoChanged(eq(true)); |
| |
| mSimulatedCommands.triggerPcoData(1, "IPV6", 1234, new byte[]{0}); |
| processAllMessages(); |
| verify(mMockedDataNetworkControllerCallback).onNrAdvancedCapableByPcoChanged(eq(false)); |
| } |
| |
| @Test |
| public void testNrAdvancedByEarlyPco() { |
| Mockito.reset(mMockedWwanDataServiceManager); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // PCO data arrives before data network entering connected state. |
| mSimulatedCommands.triggerPcoData(1, "IPV6", 1234, new byte[]{1}); |
| processAllMessages(); |
| |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mMockedWwanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| messageCaptor.capture()); |
| |
| // Send setup data call complete message. |
| Message msg = messageCaptor.getValue(); |
| msg.getData().putParcelable("data_call_response", |
| createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE)); |
| msg.arg1 = DataServiceCallback.RESULT_SUCCESS; |
| msg.sendToTarget(); |
| processAllMessages(); |
| |
| verify(mMockedDataNetworkControllerCallback).onNrAdvancedCapableByPcoChanged(eq(true)); |
| } |
| |
| @Test |
| public void testNrAdvancedByPcoMultipleNetworks() throws Exception { |
| testSetupDataNetwork(); |
| setSuccessfulSetupDataResponse(mMockedDataServiceManagers |
| .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2); |
| testSetupImsDataNetwork(); |
| |
| verify(mMockedDataNetworkControllerCallback, never()) |
| .onNrAdvancedCapableByPcoChanged(anyBoolean()); |
| mSimulatedCommands.triggerPcoData(2, "IPV6", 1234, new byte[]{1}); |
| processAllMessages(); |
| verify(mMockedDataNetworkControllerCallback).onNrAdvancedCapableByPcoChanged(eq(true)); |
| } |
| |
| @Test |
| public void testNrAdvancedByEarlyUnrelatedPco() { |
| Mockito.reset(mMockedWwanDataServiceManager); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| // Unrelated PCO data arrives before data network entering connected state. |
| mSimulatedCommands.triggerPcoData(2, "IPV6", 1234, new byte[]{1}); |
| processAllMessages(); |
| |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mMockedWwanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| messageCaptor.capture()); |
| |
| // Send setup data call complete message. |
| Message msg = messageCaptor.getValue(); |
| msg.getData().putParcelable("data_call_response", |
| createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE)); |
| msg.arg1 = DataServiceCallback.RESULT_SUCCESS; |
| msg.sendToTarget(); |
| processAllMessages(); |
| |
| verify(mMockedDataNetworkControllerCallback, never()).onNrAdvancedCapableByPcoChanged( |
| anyBoolean()); |
| } |
| |
| |
| @Test |
| public void testSetupDataNetworkVcnManaged() throws Exception { |
| // VCN managed |
| setVcnManagerPolicy(true, false); |
| NetworkRequest request = new NetworkRequest.Builder() |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) |
| .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) |
| .build(); |
| TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); |
| |
| mDataNetworkControllerUT.addNetworkRequest(tnr); |
| processAllMessages(); |
| |
| verify(mMockedDataNetworkControllerCallback) |
| .onInternetDataNetworkConnected(any()); |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| assertThat(dataNetworks).hasSize(1); |
| assertThat(dataNetworks.get(0).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)).isFalse(); |
| assertThat(dataNetworks.get(0).isInternetSupported()).isTrue(); |
| assertThat(dataNetworks.get(0).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue(); |
| } |
| |
| @Test |
| public void testSetupDataNetworkVcnRequestedTeardown() throws Exception { |
| // VCN managed, tear down on setup. |
| setVcnManagerPolicy(true, true); |
| NetworkRequest request = new NetworkRequest.Builder() |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) |
| .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) |
| .build(); |
| TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); |
| |
| mDataNetworkControllerUT.addNetworkRequest(tnr); |
| processAllMessages(); |
| |
| // Should not be any data network created. |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| assertThat(dataNetworks).hasSize(0); |
| } |
| |
| @Test |
| public void testVcnManagedNetworkPolicyChanged() throws Exception { |
| testSetupDataNetworkVcnManaged(); |
| |
| setVcnManagerPolicy(true, true); |
| ArgumentCaptor<VcnNetworkPolicyChangeListener> listenerCaptor = |
| ArgumentCaptor.forClass(VcnNetworkPolicyChangeListener.class); |
| verify(mVcnManager).addVcnNetworkPolicyChangeListener(any(Executor.class), |
| listenerCaptor.capture()); |
| |
| // Trigger policy changed event |
| VcnNetworkPolicyChangeListener listener = listenerCaptor.getValue(); |
| listener.onPolicyChanged(); |
| processAllMessages(); |
| |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| assertThat(dataNetworks).hasSize(0); |
| } |
| |
| @Test |
| public void testDataDisableNotTearingDownUnmetered() throws Exception { |
| // User data enabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, true, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| testSetupImsDataNetwork(); |
| Mockito.clearInvocations(mMockedDataNetworkControllerCallback); |
| |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // There shouldn't be any data disconnected event. |
| verify(mMockedDataNetworkControllerCallback, never()) |
| .onAnyCellularDataNetworkExistingChanged(anyBoolean()); |
| |
| // Verify IMS is still alive. |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| assertThat(dataNetworkList.get(0).getNetworkCapabilities() |
| .hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue(); |
| assertThat(dataNetworkList.get(0).isConnected()).isTrue(); |
| } |
| |
| @Test |
| public void testDataDisableTearingDownTetheringNetwork() throws Exception { |
| // User data enabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, true, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Request the restricted tethering network. |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); |
| netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| new TelephonyNetworkRequest(nativeNetworkRequest, mPhone)); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN); |
| |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Everything should be disconnected. |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testDataDisableTearingDownEnterpriseNetwork() throws Exception { |
| // User data enabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, true, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Request the restricted enterprise network. |
| testSetupEnterpriseDataNetwork(); |
| |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Everything should be disconnected. |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testSetPreferredDataProfileMultiInternetDataProfile() throws Exception { |
| // No preferred data profile in the beginning |
| doReturn(false).when(mDataProfileManager).canPreferredDataProfileSatisfy( |
| any(NetworkRequestList.class)); |
| |
| testSetupDataNetwork(); |
| |
| // Verify this network still alive after evaluation |
| mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) |
| .sendToTarget(); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| |
| // Network connected, became preferred data profile |
| doAnswer(invocation -> { |
| NetworkRequestList networkRequests = |
| (NetworkRequestList) invocation.getArguments()[0]; |
| return networkRequests.stream() |
| .allMatch(request -> request.canBeSatisfiedBy(mGeneralPurposeDataProfile)); |
| }).when(mDataProfileManager).canPreferredDataProfileSatisfy( |
| any(NetworkRequestList.class)); |
| doReturn(true).when(mDataProfileManager) |
| .isDataProfilePreferred(mGeneralPurposeDataProfile); |
| |
| // 1. Test DUN | DEFAULT data profile is compatible with preferred default internet |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_DUN)); |
| setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 2); |
| processAllMessages(); |
| |
| // Verify both DUN and preferred default network are alive |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyConnectedNetworkHasDataProfile(mTetheringDataProfile); |
| |
| // Verify this network still alive after evaluation |
| mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) |
| .sendToTarget(); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyConnectedNetworkHasDataProfile(mTetheringDataProfile); |
| |
| // 2. Test tear down when user changes preferred data profile |
| doAnswer(invocation -> { |
| NetworkRequestList networkRequests = |
| (NetworkRequestList) invocation.getArguments()[0]; |
| return networkRequests.stream() |
| .allMatch(request -> request.canBeSatisfiedBy( |
| mGeneralPurposeDataProfileAlternative)); |
| }).when(mDataProfileManager).canPreferredDataProfileSatisfy( |
| any(NetworkRequestList.class)); |
| doReturn(true).when(mDataProfileManager) |
| .isDataProfilePreferred(mGeneralPurposeDataProfileAlternative); |
| doReturn(false).when(mDataProfileManager) |
| .isDataProfilePreferred(mGeneralPurposeDataProfile); |
| |
| mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) |
| .sendToTarget(); |
| processAllMessages(); |
| |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| assertThat(dataNetworks).hasSize(1); |
| verifyConnectedNetworkHasDataProfile(mTetheringDataProfile); |
| } |
| |
| @Test |
| public void testDataDisableNotAllowingBringingUpTetheringNetwork() throws Exception { |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Request the restricted tethering network. |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); |
| netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| new TelephonyNetworkRequest(nativeNetworkRequest, mPhone)); |
| processAllMessages(); |
| |
| // Everything should be disconnected. |
| verifyAllDataDisconnected(); |
| |
| // Telephony should not try to setup a data call for DUN. |
| verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testDataDisableNotAllowingBringingUpEnterpriseNetwork() throws Exception { |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Request the restricted tethering network. |
| List<TrafficDescriptor> tdList = new ArrayList<>(); |
| tdList.add(new TrafficDescriptor.Builder() |
| .setOsAppId(new OsAppId(OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1).getBytes()) |
| .build()); |
| setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, |
| createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); |
| doReturn(mEnterpriseDataProfile).when(mDataProfileManager) |
| .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), |
| anyBoolean()); |
| |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); |
| netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| new TelephonyNetworkRequest(nativeNetworkRequest, mPhone)); |
| processAllMessages(); |
| |
| // Everything should be disconnected. |
| verifyAllDataDisconnected(); |
| |
| // Telephony should not try to setup a data call for Enterprise. |
| verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| @Test |
| public void testNonVoPSNoIMSSetup() throws Exception { |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) |
| .build(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testNonVoPStoVoPSImsSetup() throws Exception { |
| // Even allow lingering when NoVops, should have no effect on NoVops -> Vops |
| mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true); |
| carrierConfigChanged(); |
| |
| // VOPS not supported |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) |
| .build(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| // VoPS supported |
| dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) |
| .build(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testDelayImsTearDownCsRequestsToTearDown() throws Exception { |
| mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, |
| true); |
| TelephonyNetworkRequest networkRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_IMS); |
| mDataNetworkControllerUT.addNetworkRequest(networkRequest); |
| processAllMessages(); |
| |
| // Call is ongoing |
| doReturn(PhoneConstants.State.OFFHOOK).when(mCT).getState(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| verifyConnectedNetworkHasDataProfile(mImsCellularDataProfile); |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| assertThat(dataNetworks).hasSize(1); |
| dataNetworks.get(0).tearDown(DataNetwork.TEAR_DOWN_REASON_RAT_NOT_ALLOWED); |
| processAllMessages(); |
| |
| // Make sure IMS network is still connected. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| verifyConnectedNetworkHasDataProfile(mImsCellularDataProfile); |
| |
| // Now connectivity service requests to tear down the data network. |
| mDataNetworkControllerUT.removeNetworkRequest(networkRequest); |
| dataNetworks.get(0).tearDown(DataNetwork.TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED); |
| processAllMessages(); |
| |
| // All data (including IMS) should be torn down. |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testDelayImsTearDownDuringSrvcc() throws Exception { |
| testSetupImsDataNetwork(); |
| // SRVCC in progress, delay tear down |
| mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, |
| new AsyncResult(null, |
| new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_STARTED}, null)) |
| .sendToTarget(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_HSPAP, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| processAllMessages(); |
| |
| // Make sure IMS network is still connected. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // SRVCC handover ends, tear down as normal |
| mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, |
| new AsyncResult(null, |
| new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED}, null)) |
| .sendToTarget(); |
| processAllFutureMessages(); |
| |
| // Make sure IMS network is torn down |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testUnmeteredMmsWhenDataDisabled() throws Exception { |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, |
| new String[]{"default", "dun", "supl"}); |
| carrierConfigChanged(); |
| |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); |
| processAllMessages(); |
| |
| // Make sure MMS is the only capability advertised, but not internet or SUPL. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); |
| } |
| |
| @Test |
| public void testUnmeteredMmsWhenRoamingDisabled() throws Exception { |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, |
| new String[]{"default", "dun", "supl"}); |
| carrierConfigChanged(); |
| |
| // Roaming data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(false); |
| processAllMessages(); |
| |
| // Device is roaming |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); |
| processAllMessages(); |
| |
| // Make sure MMS is the only capability advertised, but not internet or SUPL. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); |
| } |
| |
| @Test |
| public void testRestrictedNetworkRequestDataDisabled() throws Exception { |
| // User data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Create a restricted network request. |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| new TelephonyNetworkRequest(nativeNetworkRequest, mPhone)); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET, |
| NetworkCapabilities.NET_CAPABILITY_SUPL, NetworkCapabilities.NET_CAPABILITY_MMS); |
| |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| // Make sure the network is restricted. |
| assertThat(dataNetworks.get(0).getNetworkCapabilities() |
| .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)).isFalse(); |
| } |
| |
| @Test |
| public void testRestrictedNetworkRequestDataEnabled() throws Exception { |
| // Create a restricted network request. |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| new TelephonyNetworkRequest(nativeNetworkRequest, mPhone)); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET, |
| NetworkCapabilities.NET_CAPABILITY_SUPL, NetworkCapabilities.NET_CAPABILITY_MMS, |
| // Because data is enabled, even though the network request is restricted, the |
| // network should still be not-restricted. |
| NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); |
| } |
| |
| @Test |
| public void testSinglePdnArbitration() throws Exception { |
| // On old 1x network, only one data network is allowed. |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_1xRTT, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_DUN)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); |
| processAllFutureMessages(); |
| // Lower priority network should not trump the higher priority network. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); |
| |
| // Now send a higher priority network request |
| TelephonyNetworkRequest fotaRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_FOTA); |
| mDataNetworkControllerUT.addNetworkRequest(fotaRequest); |
| |
| processAllFutureMessages(); |
| // The existing internet data network should be torn down. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_DUN); |
| // The higher priority emergency data network should be established. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_FOTA); |
| |
| // Now remove the fota request and tear down fota network. |
| mDataNetworkControllerUT.removeNetworkRequest(fotaRequest); |
| processAllMessages(); |
| List<DataNetwork> dataNetworks = getDataNetworks(); |
| dataNetworks.get(0).tearDown(DataNetwork.TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED); |
| processAllMessages(); |
| |
| // The tethering data network should come back since now it has the highest priority after |
| // fota is gone. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); |
| } |
| |
| @Test |
| public void testImsGracefulTearDown() throws Exception { |
| setImsRegistered(true, ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); |
| setRcsRegistered(true, ImsRegistrationImplBase.REGISTRATION_TECH_LTE); |
| |
| // IMS preferred on Wifi |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // IMS service requests an IMS network, expects the network on IWLAN. |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE); |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest( |
| nativeNetworkRequest, mPhone); |
| |
| mDataNetworkControllerUT.addNetworkRequest(networkRequest); |
| setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 2/*cid*/); |
| |
| // IMS service requests an internet network, expects the network on WWAN. |
| netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE); |
| |
| nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| networkRequest = new TelephonyNetworkRequest( |
| nativeNetworkRequest, mPhone); |
| |
| mDataNetworkControllerUT.addNetworkRequest(networkRequest); |
| |
| processAllMessages(); |
| Mockito.clearInvocations(mPhone); |
| |
| List<DataNetwork> networks = getDataNetworks(); |
| assertEquals(2, networks.size()); |
| |
| // Turn on APM mode. |
| doReturn(false).when(mSST).getDesiredPowerState(); |
| mDataNetworkControllerUT.onTearDownAllCellularDataNetworks(DataNetwork |
| .TEAR_DOWN_REASON_AIRPLANE_MODE_ON); |
| processAllMessages(); |
| |
| // Expect the network on WWAN immediately disconnected because IMS registration is on IWLAN. |
| // And it has no RCS requests. |
| assertWithMessage("Expect 1 network but have " + networks) |
| .that(networks.size()).isEqualTo(1); |
| DataNetwork wlanNetwork = networks.get(0); |
| // Expect the network on IWLAN enters stays alive. |
| assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, wlanNetwork.getTransport()); |
| assertTrue(wlanNetwork.isConnected()); |
| |
| // Turn off APM mode |
| doReturn(true).when(mSST).getDesiredPowerState(); |
| // IMS service requests an RCS network, expects the network on WWAN. |
| netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| netCaps.setRequestorPackageName(FAKE_RCS_PACKAGE); |
| |
| nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); |
| networkRequest = new TelephonyNetworkRequest( |
| nativeNetworkRequest, mPhone); |
| |
| mDataNetworkControllerUT.addNetworkRequest(networkRequest); |
| processAllMessages(); |
| |
| // Turn on APM mode again. |
| doReturn(false).when(mSST).getDesiredPowerState(); |
| mDataNetworkControllerUT.onTearDownAllCellularDataNetworks(DataNetwork |
| .TEAR_DOWN_REASON_AIRPLANE_MODE_ON); |
| processAllMessages(); |
| |
| // Expect both IMS and RCS networks are alive. |
| assertWithMessage("Expect 2 networks but only have " + networks) |
| .that(networks.size()).isEqualTo(2); |
| // Expect the network on WWAN enters disconnecting state because RCS is registered on WWAN. |
| for (DataNetwork nw : networks) { |
| if (nw.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { |
| assertTrue(nw.isConnected()); |
| } else { |
| assertTrue(nw.isDisconnecting()); |
| } |
| } |
| |
| // RCS de-registered. Now internet RCS data network is safe to be torn down. |
| // IMS de-registered. But since IMS is on IWLAN, it should remain intact. |
| Mockito.clearInvocations(mPhone); |
| setImsRegistered(false, ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); |
| setRcsRegistered(false, ImsRegistrationImplBase.REGISTRATION_TECH_LTE); |
| processAllMessages(); |
| |
| // Verify only IWLAN network exists. |
| assertTrue(mDataNetworkControllerUT.areAllCellularDataDisconnected()); |
| assertTrue(wlanNetwork.isConnected()); |
| } |
| |
| @Test |
| public void testTearDownAllCellularDataNetworks() throws Exception { |
| testSetupImsDataNetwork(); |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(true); |
| |
| List<DataNetwork> networks = getDataNetworks(); |
| |
| Mockito.reset(mMockedWlanDataServiceManager); |
| clearInvocations(mMockedDataNetworkControllerCallback); |
| // IMS preferred on WLAN |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Capture the message for setup data call response. We want to delay it. |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| messageCaptor.capture()); |
| |
| // Verify the only cellular network is handing over to WLAN |
| assertTrue(networks.get(0).isHandoverInProgress()); |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(false); |
| |
| // Turn on APM mode . |
| doReturn(false).when(mSST).getDesiredPowerState(); |
| mDataNetworkControllerUT.onTearDownAllCellularDataNetworks(DataNetwork |
| .TEAR_DOWN_REASON_AIRPLANE_MODE_ON); |
| processAllMessages(); |
| |
| assertTrue(mDataNetworkControllerUT.areAllCellularDataDisconnected()); |
| |
| // Finally WLAN handover is completed with failure. |
| Message msg = messageCaptor.getValue(); |
| DataCallResponse response = new DataCallResponse.Builder() |
| .setCause(DataFailCause.ERROR_UNSPECIFIED) |
| .setRetryDurationMillis(123) |
| .setHandoverFailureMode( |
| DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL) |
| .build(); |
| msg.getData().putParcelable("data_call_response", response); |
| msg.arg1 = DataServiceCallback.RESULT_ERROR_UNSUPPORTED; |
| msg.sendToTarget(); |
| processAllFutureMessages(); |
| |
| // WWAN network came into existence due to handover failed. |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(true); |
| // Verify disconnected after the handover failure. |
| assertTrue(mDataNetworkControllerUT.areAllCellularDataDisconnected()); |
| } |
| |
| @Test |
| public void testHandoverOnAnyCellularDataNetworkExistingChanged() throws Exception { |
| // Setup on WLAN |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, dataNetwork.getTransport()); |
| verify(mMockedDataNetworkControllerCallback, never()) |
| .onAnyCellularDataNetworkExistingChanged(anyBoolean()); |
| |
| // Change preferred transport to WWAN |
| Mockito.reset(mMockedWwanDataServiceManager); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Handing over from WLAN TO WWAN. |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(true); |
| // Capture the message for setup data call response. We want to delay it. |
| ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); |
| verify(mMockedWwanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), |
| anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), |
| messageCaptor.capture()); |
| |
| // Finally WWAN handover is completed with failure. |
| Message msg = messageCaptor.getValue(); |
| DataCallResponse response = new DataCallResponse.Builder() |
| .setCause(DataFailCause.ERROR_UNSPECIFIED) |
| .setRetryDurationMillis(123) |
| .setHandoverFailureMode( |
| DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL) |
| .build(); |
| msg.getData().putParcelable("data_call_response", response); |
| msg.arg1 = DataServiceCallback.RESULT_ERROR_UNSUPPORTED; |
| msg.sendToTarget(); |
| processAllMessages(); |
| |
| // The expected cellular is aborted due to handover failure. |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(false); |
| |
| } |
| |
| @Test |
| public void testNetworkRequestRemovedBeforeRetry() { |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.CONGESTION, |
| DataCallResponse.RETRY_DURATION_UNDEFINED, false); |
| TelephonyNetworkRequest networkRequest = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| mDataNetworkControllerUT.addNetworkRequest(networkRequest); |
| logd("Removing network request."); |
| mDataNetworkControllerUT.removeNetworkRequest(networkRequest); |
| processAllMessages(); |
| |
| // There should be only one invocation, which is the original setup data request. There |
| // shouldn't be more than 1 (i.e. should not retry). |
| verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| } |
| |
| @Test |
| public void testGetInternetDataDisallowedReasons() { |
| List<DataDisallowedReason> reasons = mDataNetworkControllerUT |
| .getInternetDataDisallowedReasons(); |
| assertThat(reasons).isEmpty(); |
| |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UNKNOWN, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); |
| |
| reasons = mDataNetworkControllerUT.getInternetDataDisallowedReasons(); |
| assertThat(reasons).containsExactly(DataDisallowedReason.NOT_IN_SERVICE, |
| DataDisallowedReason.NO_SUITABLE_DATA_PROFILE); |
| } |
| |
| @Test |
| public void testEmergencySuplDataDisabled() throws Exception { |
| // Data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| doReturn(true).when(mTelecomManager).isInEmergencyCall(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_SUPL)); |
| processAllMessages(); |
| |
| // Make sure SUPL is the only capability advertised, but not internet or MMS. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_SUPL); |
| verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMS); |
| } |
| |
| @Test |
| public void testEmergencyCallDataDisabled() throws Exception { |
| doReturn(true).when(mTelecomManager).isInEmergencyCall(); |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); |
| processAllMessages(); |
| |
| verifyInternetConnected(); |
| |
| // Data disabled |
| mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( |
| TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); |
| processAllMessages(); |
| |
| // Make sure internet is not connected. (Previously it has a bug due to incorrect logic |
| // to determine it's for emergency SUPL). |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testDataActivity() { |
| doReturn(TelephonyManager.DATA_ACTIVITY_IN).when(mLinkBandwidthEstimator).getDataActivity(); |
| mLinkBandwidthEstimatorCallback.onDataActivityChanged(TelephonyManager.DATA_ACTIVITY_IN); |
| processAllMessages(); |
| assertThat(mDataNetworkControllerUT.getDataActivity()).isEqualTo( |
| TelephonyManager.DATA_ACTIVITY_IN); |
| |
| doReturn(TelephonyManager.DATA_ACTIVITY_OUT).when(mLinkBandwidthEstimator) |
| .getDataActivity(); |
| mLinkBandwidthEstimatorCallback.onDataActivityChanged(TelephonyManager.DATA_ACTIVITY_OUT); |
| processAllMessages(); |
| assertThat(mDataNetworkControllerUT.getDataActivity()).isEqualTo( |
| TelephonyManager.DATA_ACTIVITY_OUT); |
| |
| doReturn(TelephonyManager.DATA_ACTIVITY_INOUT).when(mLinkBandwidthEstimator) |
| .getDataActivity(); |
| mLinkBandwidthEstimatorCallback.onDataActivityChanged(TelephonyManager.DATA_ACTIVITY_INOUT); |
| processAllMessages(); |
| assertThat(mDataNetworkControllerUT.getDataActivity()).isEqualTo( |
| TelephonyManager.DATA_ACTIVITY_INOUT); |
| |
| doReturn(TelephonyManager.DATA_ACTIVITY_NONE).when(mLinkBandwidthEstimator) |
| .getDataActivity(); |
| mLinkBandwidthEstimatorCallback.onDataActivityChanged(TelephonyManager.DATA_ACTIVITY_NONE); |
| processAllMessages(); |
| assertThat(mDataNetworkControllerUT.getDataActivity()).isEqualTo( |
| TelephonyManager.DATA_ACTIVITY_NONE); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkTargetOos() throws Exception { |
| // Config delay IMS tear down enabled |
| mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, |
| true); |
| carrierConfigChanged(); |
| |
| // VoPS supported |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) |
| .build(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME /*data*/, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME /*voice*/, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING /*iwlan*/, |
| dsri); |
| |
| testSetupImsDataNetwork(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| |
| // 1. Active VoPS call, mock target IWLAN OOS, should schedule retry |
| doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| // Process DRM event to schedule retry |
| processAllMessages(); |
| |
| // Verify scheduled new handover retry |
| assertTrue(mDataNetworkControllerUT.getDataRetryManager() |
| .isAnyHandoverRetryScheduled(dataNetwork)); |
| // Verify the network wasn't torn down |
| verify(mMockedWwanDataServiceManager, never()).deactivateDataCall(anyInt(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); |
| |
| // Get the scheduled retry |
| Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries"); |
| field.setAccessible(true); |
| DataRetryManager.DataHandoverRetryEntry dataRetryEntry = |
| (DataRetryManager.DataHandoverRetryEntry) ((List<DataRetryManager.DataRetryEntry>) |
| field.get(mDataNetworkControllerUT.getDataRetryManager())).get(0); |
| |
| // Process the retry |
| moveTimeForward(1000 /*The retry delay of the first attempt*/); |
| processAllMessages(); |
| |
| // Verify the previous retry is set to FAILED |
| assertEquals(DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED, dataRetryEntry.getState()); |
| // Verify a new retry is scheduled |
| assertTrue(mDataNetworkControllerUT.getDataRetryManager() |
| .isAnyHandoverRetryScheduled(dataNetwork)); |
| |
| // 2. Normal case (call ended), should tear down |
| doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); |
| mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); |
| processAllFutureMessages(); |
| |
| // Verify that handover is not performed. |
| verify(mMockedWlanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), |
| any(Message.class)); |
| |
| // Verify IMS network should be torn down. |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkSourceOos() throws Exception { |
| testSetupImsDataNetwork(); |
| // Configured handover is disallowed from OOS to 4G/5G/IWLAN. |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, |
| new String[]{ |
| "source=EUTRAN|NGRAN|IWLAN|UNKNOWN, target=EUTRAN|NGRAN|IWLAN, " |
| + "type=disallowed, capabilities=IMS|EIMS|MMS|XCAP|CBS" |
| }); |
| carrierConfigChanged(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); |
| |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Verify IMS network was torn down on source first. |
| verify(mMockedWwanDataServiceManager).deactivateDataCall(anyInt(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); |
| |
| // Verify that IWLAN is brought up again on IWLAN. |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), |
| any(Message.class)); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkRoamingOos() throws Exception { |
| testSetupImsDataNetwork(); |
| // Configured handover is disallowed at Roaming. |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, |
| new String[]{ |
| "source=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN|UNKNOWN, " |
| + "target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, roaming=true, " |
| + "type=disallowed, capabilities=IMS" |
| }); |
| carrierConfigChanged(); |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| //Enter ROAMING |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| updateServiceStateForDatatNetwork(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING, dataNetwork); |
| //OOS |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_UNKNOWN, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); |
| updateServiceStateForDatatNetwork(TelephonyManager.NETWORK_TYPE_UNKNOWN, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, |
| dataNetwork); |
| |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Verify IMS network was torn down on source first. |
| verify(mMockedWwanDataServiceManager).deactivateDataCall(anyInt(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); |
| |
| // Verify that IWLAN is brought up again on IWLAN. |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), |
| any(Message.class)); |
| |
| DataNetwork dataNetworkIwlan = getDataNetworks().get(0); |
| assertThat(dataNetworkIwlan.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| } |
| |
| private void updateServiceStateForDatatNetwork(@Annotation.NetworkType int networkType, |
| @NetworkRegistrationInfo.RegistrationState int regState, DataNetwork dataNetwork) { |
| ServiceState ss = new ServiceState(); |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(networkType) |
| .setRegistrationState(regState) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setDataSpecificInfo(null) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(networkType) |
| .setRegistrationState(regState) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_CS) |
| .build()); |
| ss.setDataRoamingFromRegistration(regState |
| == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); |
| doReturn(ss).when(mSST).getServiceState(); |
| doReturn(ss).when(mPhone).getServiceState(); |
| |
| if (dataNetwork != null) { |
| dataNetwork.obtainMessage(9/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| } |
| } |
| |
| @Test |
| public void testHandoverDataNetworkSourceOosNoUnknownRule() throws Exception { |
| testSetupImsDataNetwork(); |
| // Configured handover is allowed from OOS to 4G/5G/IWLAN. |
| mCarrierConfig.putStringArray( |
| CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, |
| new String[]{ |
| "source=EUTRAN|NGRAN|IWLAN, target=EUTRAN|NGRAN|IWLAN, " |
| + "type=disallowed, capabilities=IMS|EIMS|MMS|XCAP|CBS" |
| }); |
| carrierConfigChanged(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); |
| |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Verify IMS network was torn down on source first. |
| verify(mMockedWwanDataServiceManager).deactivateDataCall(anyInt(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); |
| |
| // Verify that IWLAN is brought up again on IWLAN. |
| verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), |
| any(Message.class)); |
| |
| DataNetwork dataNetwork = getDataNetworks().get(0); |
| assertThat(dataNetwork.getTransport()).isEqualTo( |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkNonVops() throws Exception { |
| ServiceState ss = new ServiceState(); |
| |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) |
| .build(); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setDataSpecificInfo(dsri) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_CS) |
| .build()); |
| processServiceStateRegStateForTest(ss); |
| doReturn(ss).when(mSST).getServiceState(); |
| doReturn(ss).when(mPhone).getServiceState(); |
| |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Change the preference to cellular |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Verify that handover is not performed. |
| verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| // IMS network should be torn down. |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testHandoverDataNetworkNonVopsAllowLingeringVoPS() throws Exception { |
| // Allow lingering IMS PDN when enter area VoPS -> no VoPS |
| mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true); |
| carrierConfigChanged(); |
| |
| ServiceState ss = new ServiceState(); |
| |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) |
| .build(); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setDataSpecificInfo(dsri) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_CS) |
| .build()); |
| processServiceStateRegStateForTest(ss); |
| doReturn(ss).when(mSST).getServiceState(); |
| doReturn(ss).when(mPhone).getServiceState(); |
| |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Change the preference to cellular |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Verify that handover is not performed. |
| verify(mMockedWwanDataServiceManager).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| // IMS network still alive. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testNonMmtelImsHandoverDataNetworkNonVops() throws Exception { |
| ServiceState ss = new ServiceState(); |
| |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) |
| .build(); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setDataSpecificInfo(dsri) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_CS) |
| .build()); |
| processServiceStateRegStateForTest(ss); |
| doReturn(ss).when(mSST).getServiceState(); |
| doReturn(ss).when(mPhone).getServiceState(); |
| |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| |
| // Bring up the IMS network that does not require MMTEL |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); |
| processAllMessages(); |
| |
| // Even though the network request does not have MMTEL, but the network support it, so |
| // the network capabilities should still have MMTEL. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Change the preference to cellular |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WWAN); |
| |
| // Verify that handover is performed |
| verify(mMockedWwanDataServiceManager).setupDataCall(anyInt(), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| // The IMS network should still have IMS and MMTEL. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testMmtelImsDataNetworkMovingToNonVops() throws Exception { |
| // Allow lingering IMS PDN when enter area VoPS -> no VoPS |
| mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true); |
| carrierConfigChanged(); |
| |
| ServiceState ss = new ServiceState(); |
| |
| // VoPS network |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) |
| .build(); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setDataSpecificInfo(dsri) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_CS) |
| .build()); |
| processServiceStateRegStateForTest(ss); |
| doReturn(ss).when(mSST).getServiceState(); |
| doReturn(ss).when(mPhone).getServiceState(); |
| |
| doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) |
| .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| |
| // Bring up the IMS network that does require MMTEL |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| |
| // the network capabilities should have IMS and MMTEL. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| ss = new ServiceState(); |
| // Non VoPS network |
| dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) |
| .build(); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .setDataSpecificInfo(dsri) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_PS) |
| .build()); |
| |
| ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() |
| .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) |
| .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) |
| .setDomain(NetworkRegistrationInfo.DOMAIN_CS) |
| .build()); |
| processServiceStateRegStateForTest(ss); |
| doReturn(ss).when(mSST).getServiceState(); |
| doReturn(ss).when(mPhone).getServiceState(); |
| |
| mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| processAllMessages(); |
| |
| // The IMS network is alive due to KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL = true |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, false); |
| carrierConfigChanged(); |
| mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) |
| .sendToTarget(); |
| processAllMessages(); |
| |
| // The IMS network should be torn down by data network controller. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testVoPStoNonVoPSDelayImsTearDown() throws Exception { |
| mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, |
| true); |
| carrierConfigChanged(); |
| |
| // VoPS supported |
| DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) |
| .build(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| doReturn(PhoneConstants.State.OFFHOOK).when(mCT).getState(); |
| |
| dsri = new DataSpecificRegistrationInfo.Builder(8) |
| .setNrAvailable(true) |
| .setEnDcAvailable(true) |
| .setVopsSupportInfo(new LteVopsSupportInfo( |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, |
| LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) |
| .build(); |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); |
| |
| // Make sure IMS is still connected. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| |
| // Call ends |
| doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); |
| mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); |
| processAllMessages(); |
| |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| } |
| |
| @Test |
| public void testDeactivateDataOnOldHal() throws Exception { |
| doAnswer(invocation -> { |
| // Only send the deactivation data response, no data call list changed event. |
| Message msg = (Message) invocation.getArguments()[2]; |
| msg.sendToTarget(); |
| return null; |
| }).when(mMockedWwanDataServiceManager).deactivateDataCall( |
| anyInt(), anyInt(), any(Message.class)); |
| // Simulate old devices |
| doReturn(RIL.RADIO_HAL_VERSION_1_6).when(mPhone).getHalVersion(HAL_SERVICE_DATA); |
| |
| testSetupDataNetwork(); |
| |
| mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, |
| TelephonyManager.SIM_STATE_ABSENT, 0).sendToTarget(); |
| processAllMessages(); |
| verifyAllDataDisconnected(); |
| verify(mMockedDataNetworkControllerCallback).onAnyCellularDataNetworkExistingChanged(false); |
| verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); |
| verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( |
| eq(DataCallResponse.LINK_STATUS_INACTIVE)); |
| } |
| |
| @Test |
| public void testHandoverWhileSetupDataCallInProgress() throws Exception { |
| // Long delay setup failure |
| setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.CONGESTION, |
| DataCallResponse.RETRY_DURATION_UNDEFINED, false, 10000); |
| |
| mDataNetworkControllerUT.addNetworkRequest( |
| createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL)); |
| processAllMessages(); |
| |
| // Change the preference to IWLAN while setup data is still ongoing. |
| updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, |
| AccessNetworkConstants.TRANSPORT_TYPE_WLAN); |
| |
| // Data should not be connected. |
| verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); |
| |
| // There shouldn't be any attempt to bring up IMS on IWLAN even though the preference |
| // has already changed, because the previous setup is still ongoing. |
| verify(mMockedWlanDataServiceManager, never()).setupDataCall(eq(AccessNetworkType.IWLAN), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), |
| any(), any(), anyBoolean(), any(Message.class)); |
| |
| processAllFutureMessages(); |
| |
| // Should setup a new one instead of handover. |
| verify(mMockedWlanDataServiceManager).setupDataCall(eq(AccessNetworkType.IWLAN), |
| any(DataProfile.class), anyBoolean(), anyBoolean(), |
| eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), |
| any(Message.class)); |
| |
| // IMS should be connected. |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, |
| NetworkCapabilities.NET_CAPABILITY_MMTEL); |
| } |
| |
| @Test |
| public void testRemoveNetworkRequest() throws Exception { |
| NetworkCapabilities netCaps = new NetworkCapabilities(); |
| netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| |
| NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps, |
| ConnectivityManager.TYPE_MOBILE, 0, NetworkRequest.Type.REQUEST); |
| |
| mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest( |
| nativeNetworkRequest, mPhone)); |
| processAllMessages(); |
| |
| // Intentionally create a new telephony request with the original native network request. |
| TelephonyNetworkRequest request = new TelephonyNetworkRequest(nativeNetworkRequest, mPhone); |
| |
| mDataNetworkControllerUT.removeNetworkRequest(request); |
| processAllFutureMessages(); |
| |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| // The data network should not be torn down after network request removal. |
| assertThat(dataNetworkList).hasSize(1); |
| // But should be detached from the data network. |
| assertThat(dataNetworkList.get(0).getAttachedNetworkRequestList()).isEmpty(); |
| assertThat(dataNetworkList.get(0).isConnected()).isTrue(); |
| } |
| |
| @Test |
| public void testTempDdsSwitchTearDown() throws Exception { |
| TelephonyNetworkRequest request = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_INTERNET); |
| mDataNetworkControllerUT.addNetworkRequest(request); |
| processAllMessages(); |
| |
| // this slot is 0, modem preferred on slot 1 |
| doReturn(1).when(mMockedPhoneSwitcher).getPreferredDataPhoneId(); |
| |
| // Simulate telephony network factory remove request due to switch. |
| mDataNetworkControllerUT.removeNetworkRequest(request); |
| processAllMessages(); |
| |
| // Data should be torn down on this non-preferred sub. |
| verifyAllDataDisconnected(); |
| } |
| |
| @Test |
| public void testSetupDataOnNonDds() throws Exception { |
| // this slot is 0, modem preferred on slot 1 |
| doReturn(1).when(mMockedPhoneSwitcher).getPreferredDataPhoneId(); |
| TelephonyNetworkRequest request = createNetworkRequest( |
| NetworkCapabilities.NET_CAPABILITY_MMS); |
| |
| // Test Don't allow setup if both data and voice OOS |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_1xRTT, |
| // data, voice, Iwlan reg state |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null); |
| mDataNetworkControllerUT.addNetworkRequest(request); |
| processAllMessages(); |
| |
| verifyAllDataDisconnected(); |
| |
| // Test Don't allow setup if CS is in service, but current RAT is already PS(e.g. LTE) |
| serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null); |
| |
| verifyAllDataDisconnected(); |
| |
| // Test Allow if voice is in service if RAT is 2g/3g, use voice RAT to select data profile |
| ServiceState ss = createSS(TelephonyManager.NETWORK_TYPE_UNKNOWN /* data RAT */, |
| TelephonyManager.NETWORK_TYPE_1xRTT /* voice RAT */, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING , |
| NetworkRegistrationInfo.REGISTRATION_STATE_HOME, |
| NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null); |
| doReturn(ss).when(mSST).getServiceState(); |
| mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); |
| mDataNetworkControllerUT.removeNetworkRequest(request); |
| mDataNetworkControllerUT.addNetworkRequest(request); |
| processAllMessages(); |
| |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); |
| } |
| |
| @Test |
| public void testTrafficDescriptionChangedDataRetry() throws Exception { |
| List<TrafficDescriptor> tdList = List.of( |
| new TrafficDescriptor.Builder() |
| .setOsAppId(new OsAppId(OsAppId.ANDROID_OS_ID, "PRIORITIZE_LATENCY", 1) |
| .getBytes()).build(), |
| new TrafficDescriptor.Builder() |
| .setOsAppId(new OsAppId(OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1).getBytes()) |
| .build() |
| ); |
| setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, |
| createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); |
| doReturn(mEnterpriseDataProfile).when(mDataProfileManager) |
| .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), |
| anyBoolean()); |
| mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest( |
| new NetworkRequest.Builder() |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE) |
| .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) |
| .build(), mPhone)); |
| processAllMessages(); |
| verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE, |
| NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY); |
| |
| mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest( |
| new NetworkRequest.Builder() |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) |
| .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) |
| .build(), mPhone)); |
| processAllMessages(); |
| List<DataNetwork> dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(1); |
| |
| // Now remove low latency TD from the data call response. |
| logd("Now remove PRIORITIZE_LATENCY"); |
| tdList = List.of(new TrafficDescriptor.Builder() |
| .setOsAppId(new OsAppId(OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1).getBytes()) |
| .build()); |
| mDataCallResponses.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).put(1, |
| createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); |
| mDataCallListChangedRegistrants.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) |
| .notifyRegistrants(new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, |
| List.of(createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, |
| tdList)), null)); |
| |
| tdList = List.of(new TrafficDescriptor.Builder() |
| .setOsAppId(new OsAppId(OsAppId.ANDROID_OS_ID, "PRIORITIZE_LATENCY", 1).getBytes()) |
| .build()); |
| setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, |
| createDataCallResponse(2, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); |
| doReturn(mLowLatencyDataProfile).when(mDataProfileManager) |
| .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), |
| anyBoolean()); |
| processAllFutureMessages(); |
| |
| dataNetworkList = getDataNetworks(); |
| assertThat(dataNetworkList).hasSize(2); |
| |
| assertThat(dataNetworkList.get(0).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isTrue(); |
| assertThat(dataNetworkList.get(0).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)).isFalse(); |
| assertThat(dataNetworkList.get(1).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isFalse(); |
| assertThat(dataNetworkList.get(1).getNetworkCapabilities().hasCapability( |
| NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)).isTrue(); |
| } |
| } |