blob: ad9fe43c38a542dc20aaba9ece28eaabc456ad20 [file] [log] [blame]
/*
* Copyright (C) 2016 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.dataconnection;
import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
import static com.android.internal.telephony.dataconnection.ApnSettingTest.createApnSetting;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.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.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.hardware.radio.V1_0.SetupDataCallResult;
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.SystemClock;
import android.provider.Settings;
import android.provider.Telephony;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.Annotation;
import android.telephony.CarrierConfigManager;
import android.telephony.DataFailCause;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
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.DataProfile;
import android.telephony.data.DataService;
import android.telephony.data.TrafficDescriptor;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import android.util.Pair;
import android.util.SparseArray;
import androidx.test.filters.FlakyTest;
import com.android.internal.R;
import com.android.internal.telephony.DctConstants;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.data.CellularDataService;
import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.Period;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class DcTrackerTest extends TelephonyTest {
public static final String FAKE_APN1 = "FAKE APN 1";
public static final String FAKE_APN2 = "FAKE APN 2";
public static final String FAKE_APN3 = "FAKE APN 3";
public static final String FAKE_APN4 = "FAKE APN 4";
public static final String FAKE_APN5 = "FAKE APN 5";
public static final String FAKE_APN6 = "FAKE APN 6";
public static final String FAKE_APN7 = "FAKE APN 7";
public static final String FAKE_APN8 = "FAKE APN 8";
public static final String FAKE_APN9 = "FAKE APN 9";
public static final String FAKE_IFNAME = "FAKE IFNAME";
public static final String FAKE_PCSCF_ADDRESS = "22.33.44.55";
public static final String FAKE_GATEWAY = "11.22.33.44";
public static final String FAKE_DNS = "55.66.77.88";
public static final String FAKE_ADDRESS = "99.88.77.66";
private static final int NETWORK_TYPE_NR_BITMASK =
1 << (TelephonyManager.NETWORK_TYPE_NR - 1);
private static final int NETWORK_TYPE_LTE_BITMASK =
1 << (TelephonyManager.NETWORK_TYPE_LTE - 1);
private static final int NETWORK_TYPE_EHRPD_BITMASK =
1 << (TelephonyManager.NETWORK_TYPE_EHRPD - 1);
private static final Uri PREFERAPN_URI = Uri.parse(
Telephony.Carriers.CONTENT_URI + "/preferapn");
private static final int DATA_ENABLED_CHANGED = 0;
private static final String FAKE_PLMN = "44010";
private static final long TEST_TIMEOUT = 1000;
// Mocked classes
ISub mIsub;
IBinder mBinder;
SubscriptionInfo mSubscriptionInfo;
ApnContext mApnContext;
DataConnection mDataConnection;
Handler mHandler;
NetworkPolicyManager mNetworkPolicyManager;
private DcTracker mDct;
private DcTrackerTestHandler mDcTrackerTestHandler;
private AlarmManager mAlarmManager;
private PersistableBundle mBundle;
private SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
private final ApnSettingContentProvider mApnSettingContentProvider =
new ApnSettingContentProvider();
private Message mMessage;
private CellularDataService mCellularDataService;
private void addDataService() {
mCellularDataService = new CellularDataService();
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.packageName = "com.android.phone";
serviceInfo.permission = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
IntentFilter filter = new IntentFilter();
mContextFixture.addService(
DataService.SERVICE_INTERFACE,
null,
"com.android.phone",
mCellularDataService.mBinder,
serviceInfo,
filter);
}
private class DcTrackerTestHandler extends HandlerThread {
private DcTrackerTestHandler(String name) {
super(name);
}
@Override
public void onLooperPrepared() {
mDct = new DcTracker(mPhone, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
setReady(true);
}
}
private class ApnSettingContentProvider extends MockContentProvider {
public final String[] FAKE_APN_COLUMNS = new String[]{
Telephony.Carriers._ID, Telephony.Carriers.NUMERIC,
Telephony.Carriers.NAME, Telephony.Carriers.APN,
Telephony.Carriers.PROXY, Telephony.Carriers.PORT,
Telephony.Carriers.MMSC, Telephony.Carriers.MMSPROXY,
Telephony.Carriers.MMSPORT, Telephony.Carriers.USER,
Telephony.Carriers.PASSWORD, Telephony.Carriers.AUTH_TYPE,
Telephony.Carriers.TYPE,
Telephony.Carriers.PROTOCOL,
Telephony.Carriers.ROAMING_PROTOCOL,
Telephony.Carriers.CARRIER_ENABLED, Telephony.Carriers.BEARER,
Telephony.Carriers.BEARER_BITMASK,
Telephony.Carriers.PROFILE_ID,
Telephony.Carriers.MODEM_PERSIST,
Telephony.Carriers.MAX_CONNECTIONS,
Telephony.Carriers.WAIT_TIME_RETRY,
Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS,
Telephony.Carriers.MTU,
Telephony.Carriers.MTU_V4,
Telephony.Carriers.MTU_V6,
Telephony.Carriers.MVNO_TYPE,
Telephony.Carriers.MVNO_MATCH_DATA,
Telephony.Carriers.NETWORK_TYPE_BITMASK,
Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK,
Telephony.Carriers.APN_SET_ID,
Telephony.Carriers.CARRIER_ID,
Telephony.Carriers.SKIP_464XLAT,
Telephony.Carriers.ALWAYS_ON
};
private int mPreferredApnSet = 0;
private Object[] mPreferredApn = null;
private String mFakeApn1Types = "default,supl";
private String mFakeApn5Types = "dun";
private int mFakeApn1Bitmask = NETWORK_TYPE_LTE_BITMASK;
private int mRowIdOffset = 0;
public void setFakeApn1Types(String apnTypes) {
mFakeApn1Types = apnTypes;
}
public void setFakeApn5Types(String apnTypes) {
mFakeApn5Types = apnTypes;
}
public void setFakeApn1NetworkTypeBitmask(int bitmask) {
mFakeApn1Bitmask = bitmask;
}
public void setRowIdOffset(int rowIdOffset) {
mRowIdOffset = rowIdOffset;
}
public void setFakePreferredApn(Object[] fakeApn) {
mPreferredApn = fakeApn;
}
public Object[] getFakeApn1() {
return new Object[]{
2163 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"sp-mode", // name
FAKE_APN1, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
mFakeApn1Types, // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer
0, // bearer_bitmask
0, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
mFakeApn1Bitmask, // network_type_bitmask
0, // lingering_network_type_bitmask
0, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn2() {
return new Object[]{
2164 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"mopera U", // name
FAKE_APN2, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
"default,supl", // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer,
0, // bearer_bitmask
0, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
0, // lingering_network_type_bitmask
0, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn3() {
return new Object[]{
2165 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"b-mobile for Nexus", // name
FAKE_APN3, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
"ims", // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
0, // bearer
0, // bearer_bitmask
2, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
0, // network_type_bitmask
0, // lingering_network_type_bitmask
0, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn4() {
return new Object[]{
2166 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"sp-mode ehrpd", // name
FAKE_APN4, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
"default,supl", // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD, // bearer
0, // bearer_bitmask
0, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
NETWORK_TYPE_EHRPD_BITMASK, // network_type_bitmask
0, // lingering_network_type_bitmask
0, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn5() {
return new Object[]{
2167 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"b-mobile for Nexus", // name
FAKE_APN5, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
mFakeApn5Types, // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
0, // bearer
0, // bearer_bitmask
0, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
0, // network_type_bitmask
0, // lingering_network_type_bitmask
0, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn6() {
return new Object[]{
2168 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"sp-mode", // name
FAKE_APN6, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
"mms,xcap", // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer
0, // bearer_bitmask
0, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
0, // lingering_network_type_bitmask
0, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn7() {
return new Object[]{
2169 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"sp-mode", // name
FAKE_APN7, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
"default", // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer
0, // bearer_bitmask
0, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
0, // lingering_network_type_bitmask
1, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn8() {
return new Object[]{
2170 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"IMS", // name
FAKE_APN8, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
"ims", // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer
0, // bearer_bitmask
2, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
0, // lingering_network_type_bitmask
-1, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
public Object[] getFakeApn9() {
return new Object[]{
2171 + mRowIdOffset, // id
FAKE_PLMN, // numeric
"sp-mode nr", // name
FAKE_APN9, // apn
"", // proxy
"", // port
"", // mmsc
"", // mmsproxy
"", // mmsport
"", // user
"", // password
-1, // authtype
"default,enterprise", // types
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer
0, // bearer_bitmask
0, // profile_id
1, // modem_cognitive
0, // max_conns
0, // wait_time
0, // max_conns_time
0, // mtu
0, // mtu_v4
0, // mtu_v6
"", // mvno_type
"", // mnvo_match_data
NETWORK_TYPE_NR_BITMASK, // network_type_bitmask
0, // lingering_network_type_bitmask
0, // apn_set_id
-1, // carrier_id
-1, // skip_464xlat
0 // always_on
};
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
logd("ApnSettingContentProvider: query");
logd(" uri = " + uri);
logd(" projection = " + Arrays.toString(projection));
logd(" selection = " + selection);
logd(" selectionArgs = " + Arrays.toString(selectionArgs));
logd(" sortOrder = " + sortOrder);
if (uri.compareTo(Telephony.Carriers.CONTENT_URI) == 0
|| uri.toString().startsWith(Uri.withAppendedPath(
Telephony.Carriers.CONTENT_URI, "filtered").toString())
|| uri.toString().startsWith(Uri.withAppendedPath(
Telephony.Carriers.SIM_APN_URI, "filtered").toString())) {
if (projection == null) {
logd("Query '" + FAKE_PLMN + "' APN settings");
MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS);
mc.addRow(getFakeApn1());
mc.addRow(getFakeApn2());
mc.addRow(getFakeApn3());
mc.addRow(getFakeApn4());
mc.addRow(getFakeApn5());
mc.addRow(getFakeApn6());
mc.addRow(getFakeApn7());
mc.addRow(getFakeApn8());
mc.addRow(getFakeApn9());
return mc;
}
} else if (isPathPrefixMatch(uri,
Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapnset"))) {
MatrixCursor mc = new MatrixCursor(
new String[]{Telephony.Carriers.APN_SET_ID});
// apn_set_id is the only field used with this URL
mc.addRow(new Object[]{ mPreferredApnSet });
mc.addRow(new Object[]{ 0 });
return mc;
} else if (isPathPrefixMatch(uri,
Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapn_no_update"))) {
if (mPreferredApn == null) {
return null;
} else {
MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS);
mc.addRow(mPreferredApn);
return mc;
}
}
return null;
}
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
mPreferredApnSet = values.getAsInteger(Telephony.Carriers.APN_SET_ID);
return 1;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
}
@Before
public void setUp() throws Exception {
logd("DcTrackerTest +Setup!");
super.setUp(getClass().getSimpleName());
mIsub = Mockito.mock(ISub.class);
mBinder = Mockito.mock(IBinder.class);
mSubscriptionInfo = Mockito.mock(SubscriptionInfo.class);
mApnContext = Mockito.mock(ApnContext.class);
mDataConnection = Mockito.mock(DataConnection.class);
mHandler = Mockito.mock(Handler.class);
mNetworkPolicyManager = Mockito.mock(NetworkPolicyManager.class);
doReturn("fake.action_detached").when(mPhone).getActionDetached();
doReturn("fake.action_attached").when(mPhone).getActionAttached();
doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState)
.getRilDataRadioTechnology();
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mContextFixture.putStringArrayResource(com.android.internal.R.array
.config_mobile_tcp_buffers, new String[]{
"umts:131072,262144,1452032,4096,16384,399360",
"hspa:131072,262144,2441216,4096,16384,399360",
"hsupa:131072,262144,2441216,4096,16384,399360",
"hsdpa:131072,262144,2441216,4096,16384,399360",
"hspap:131072,262144,2441216,4096,16384,399360",
"edge:16384,32768,131072,4096,16384,65536",
"gprs:4096,8192,24576,4096,8192,24576",
"1xrtt:16384,32768,131070,4096,16384,102400",
"evdo:131072,262144,1048576,4096,16384,524288",
"lte:524288,1048576,8388608,262144,524288,4194304"});
mContextFixture.putResource(R.string.config_wwan_data_service_package,
"com.android.phone");
((MockContentResolver) mContext.getContentResolver()).addProvider(
Telephony.Carriers.CONTENT_URI.getAuthority(), mApnSettingContentProvider);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mTransportManager)
.getPreferredTransport(anyInt());
doReturn(PhoneConstants.State.IDLE).when(mCT).getState();
doReturn(true).when(mSST).getDesiredPowerState();
doReturn(true).when(mSST).getPowerStateFromCarrier();
doAnswer(
(Answer<Void>) invocation -> {
mOnSubscriptionsChangedListener =
(SubscriptionManager.OnSubscriptionsChangedListener)
invocation.getArguments()[0];
return null;
}
).when(mSubscriptionManager).addOnSubscriptionsChangedListener(any());
doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
doReturn(mNetworkPolicyManager).when(mContext)
.getSystemService(Context.NETWORK_POLICY_SERVICE);
doReturn(1).when(mIsub).getDefaultDataSubId();
doReturn(mIsub).when(mBinder).queryLocalInterface(anyString());
mServiceManagerMockedServices.put("isub", mBinder);
mContextFixture.putStringArrayResource(
com.android.internal.R.array.config_cell_retries_per_error_code,
new String[]{"36,2"});
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mBundle = mContextFixture.getCarrierConfigBundle();
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
addDataService();
mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName());
mDcTrackerTestHandler.start();
waitUntilReady();
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId());
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
mContext.sendBroadcast(intent);
waitForMs(600);
logd("DcTrackerTest -Setup!");
}
@After
public void tearDown() throws Exception {
logd("DcTrackerTest -tearDown");
mDct.removeCallbacksAndMessages(null);
mDct.stopHandlerThread();
mDct = null;
mDcTrackerTestHandler.quit();
mDcTrackerTestHandler.join();
mDcTrackerTestHandler = null;
mCellularDataService.onDestroy();
mCellularDataService = null;
mAlarmManager = null;
mBundle = null;
mCellularDataService = null;
waitForMs(100);
super.tearDown();
}
// Create a successful data response
private static SetupDataCallResult createSetupDataCallResult() {
SetupDataCallResult result = new SetupDataCallResult();
result.status = 0;
result.suggestedRetryTime = -1;
result.cid = 1;
result.active = 2;
result.type = "IP";
result.ifname = FAKE_IFNAME;
result.addresses = FAKE_ADDRESS;
result.dnses = FAKE_DNS;
result.gateways = FAKE_GATEWAY;
result.pcscf = FAKE_PCSCF_ADDRESS;
result.mtu = 1440;
return result;
}
private void verifyDataProfile(DataProfile dp, String apn, int profileId,
int supportedApnTypesBitmap, int type, int bearerBitmask) {
assertEquals(profileId, dp.getProfileId());
assertEquals(apn, dp.getApn());
assertEquals(ApnSetting.PROTOCOL_IP, dp.getProtocolType());
assertEquals(0, dp.getAuthType());
assertEquals("", dp.getUserName());
assertEquals("", dp.getPassword());
assertEquals(type, dp.getType());
assertEquals(0, dp.getWaitTime());
assertTrue(dp.isEnabled());
assertEquals(supportedApnTypesBitmap, dp.getSupportedApnTypesBitmask());
assertEquals(ApnSetting.PROTOCOL_IP, dp.getRoamingProtocolType());
assertEquals(bearerBitmask, dp.getBearerBitmask());
assertEquals(0, dp.getMtu());
assertTrue(dp.isPersistent());
assertFalse(dp.isPreferred());
}
private void verifyDataConnected(final String apnSetting) {
verify(mAlarmManager, times(1)).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
any(PendingIntent.class));
assertEquals(apnSetting, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING));
assertArrayEquals(new String[]{ApnSetting.TYPE_DEFAULT_STRING}, mDct.getActiveApnTypes());
assertTrue(mDct.isAnyDataConnected());
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
LinkProperties linkProperties = mDct.getLinkProperties(ApnSetting.TYPE_DEFAULT_STRING);
assertEquals(FAKE_IFNAME, linkProperties.getInterfaceName());
assertEquals(1, linkProperties.getAddresses().size());
assertEquals(FAKE_ADDRESS, linkProperties.getAddresses().get(0).getHostAddress());
assertEquals(1, linkProperties.getDnsServers().size());
assertEquals(FAKE_DNS, linkProperties.getDnsServers().get(0).getHostAddress());
assertEquals(FAKE_GATEWAY, linkProperties.getRoutes().get(0).getGateway().getHostAddress());
}
private boolean isHandoverPending(int apnType) {
try {
Method method = DcTracker.class.getDeclaredMethod("isHandoverPending",
int.class);
method.setAccessible(true);
return (boolean) method.invoke(mDct, apnType);
} catch (Exception e) {
fail(e.toString());
return false;
}
}
private void addHandoverCompleteMsg(Message onCompleteMsg,
@Annotation.ApnType int apnType) {
try {
Method method = DcTracker.class.getDeclaredMethod("addHandoverCompleteMsg",
Message.class, int.class);
method.setAccessible(true);
method.invoke(mDct, onCompleteMsg, apnType);
} catch (Exception e) {
fail(e.toString());
}
}
private void sendInitializationEvents() {
sendCarrierConfigChanged("");
sendSimStateUpdated("");
sendEventDataConnectionAttached("");
waitForMs(200);
}
private void sendCarrierConfigChanged(String messagePrefix) {
logd(messagePrefix + "Sending EVENT_CARRIER_CONFIG_CHANGED");
mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
private void sendSimStateUpdated(String messagePrefix) {
logd(messagePrefix + "Sending EVENT_SIM_STATE_UPDATED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED,
TelephonyManager.SIM_STATE_LOADED, 0));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
private void sendEventDataConnectionAttached(String messagePrefix) {
logd(messagePrefix + "Sending EVENT_DATA_CONNECTION_ATTACHED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
// Test the unmetered APN setup when data is disabled.
@Test
@SmallTest
public void testTrySetupDataUnmeteredDefaultNotSelected() throws Exception {
initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING});
doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mIsub).getDefaultDataSubId();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
sendInitializationEvents();
mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the normal data call setup scenario.
@Test
@MediumTest
public void testDataSetup() throws Exception {
DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
boolean allowed = mDct.isDataAllowed(dataConnectionReasons);
assertFalse(dataConnectionReasons.toString(), allowed);
logd("Sending EVENT_ENABLE_APN");
// APN id 0 is APN_TYPE_DEFAULT
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
sendInitializationEvents();
dataConnectionReasons = new DataConnectionReasons();
allowed = mDct.isDataAllowed(dataConnectionReasons);
assertTrue(dataConnectionReasons.toString(), allowed);
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
verifyDataConnected(FAKE_APN1);
}
// Test the scenario where the first data call setup is failed, and then retry the setup later.
@Test
@MediumTest
public void testDataRetry() throws Exception {
AsyncResult ar = new AsyncResult(null,
new Pair<>(true, DataEnabledSettings.REASON_USER_DATA_ENABLED), null);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// LOST_CONNECTION(0x10004) is a non-permanent failure, so we'll retry data setup later.
SetupDataCallResult result = createSetupDataCallResult();
result.status = 0x10004;
// Simulate RIL fails the data call setup
mSimulatedCommands.setDataCallResult(true, result);
DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
boolean allowed = mDct.isDataAllowed(dataConnectionReasons);
assertFalse(dataConnectionReasons.toString(), allowed);
logd("Sending EVENT_ENABLE_APN");
// APN id 0 is APN_TYPE_DEFAULT
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
sendInitializationEvents();
dataConnectionReasons = new DataConnectionReasons();
allowed = mDct.isDataAllowed(dataConnectionReasons);
assertTrue(dataConnectionReasons.toString(), allowed);
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
// This time we'll let RIL command succeed.
mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult());
//Send event for reconnecting data
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
mPhone.getPhoneId(), DcTracker.REQUEST_TYPE_NORMAL, mApnContext));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
// Verify connected with APN2 setting.
verifyDataConnected(FAKE_APN2);
}
@Test
@MediumTest
@Ignore
@FlakyTest
public void testUserDisableData() {
//step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS
//set Default and MMS to be metered in the CarrierConfigManager
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK);
logd("Sending DATA_DISABLED_CMD");
doReturn(false).when(mDataEnabledSettings).isDataEnabled();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
AsyncResult ar = new AsyncResult(null,
new Pair<>(false, DataEnabledSettings.REASON_USER_DATA_ENABLED), null);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// expected tear down all metered DataConnections
verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
any(Message.class));
assertTrue(mDct.isAnyDataConnected());
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING));
}
@Test
@MediumTest
public void testTrySetupDataMmsAllowedDataDisabled() {
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
List<DataProfile> dataProfiles = dpCaptor.getAllValues();
assertEquals(2, dataProfiles.size());
//Verify FAKE_APN1
Optional<DataProfile> fakeApn1 = dataProfiles.stream()
.filter(dp -> dp.getApn().equals(FAKE_APN1))
.findFirst();
assertTrue(fakeApn1.isPresent());
verifyDataProfile(fakeApn1.get(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
//Verify FAKE_APN6
Optional<DataProfile> fakeApn6 = dataProfiles.stream()
.filter(dp -> dp.getApn().equals(FAKE_APN6))
.findFirst();
assertTrue(fakeApn6.isPresent());
verifyDataProfile(fakeApn6.get(), FAKE_APN6, 0, ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP,
1, NETWORK_TYPE_LTE_BITMASK);
logd("Sending DATA_DISABLED_CMD for default data");
doReturn(false).when(mDataEnabledSettings).isDataEnabled();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget();
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// expected tear down all metered DataConnections
verify(mSimulatedCommandsVerifier, times(2)).deactivateDataCall(
anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class));
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING));
clearInvocations(mSimulatedCommandsVerifier);
doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS);
mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget();
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING));
}
@Test
@MediumTest
public void testTrySetupDataMmsAlwaysAllowedDataDisabled() {
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mApnSettingContentProvider.setFakeApn1Types("mms,xcap,default");
mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
// Verify MMS was set up and is connected
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0,
ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP | ApnSetting.TYPE_DEFAULT,
1, NETWORK_TYPE_LTE_BITMASK);
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING));
// Verify DC has all capabilities specified in fakeApn1Types
Map<Integer, ApnContext> apnContexts = mDct.getApnContexts().stream().collect(
Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection()
.getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS));
assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection()
.getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP));
assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection()
.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_INTERNET));
// Disable mobile data
doReturn(false).when(mDataEnabledSettings).isDataEnabled();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
doReturn(false).when(mDataEnabledSettings).isMmsAlwaysAllowed();
mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget();
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Expected tear down all metered DataConnections
waitForMs(200);
verify(mSimulatedCommandsVerifier).deactivateDataCall(
anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class));
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING));
// Allow MMS unconditionally
clearInvocations(mSimulatedCommandsVerifier);
doReturn(true).when(mDataEnabledSettings).isMmsAlwaysAllowed();
doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS);
mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget();
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Verify MMS was set up and is connected
waitForMs(200);
verify(mSimulatedCommandsVerifier).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING));
// Ensure MMS data connection has the MMS capability only.
apnContexts = mDct.getApnContexts().stream().collect(
Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection()
.getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS));
assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection()
.getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP));
assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection()
.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_INTERNET));
}
@Test
@MediumTest
public void testUserDisableRoaming() {
//step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS
//step 2: set roaming disabled, data is enabled
//step 3: under roaming service
//step 4: only tear down metered data connections.
//set Default and MMS to be metered in the CarrierConfigManager
boolean roamingEnabled = mDct.getDataRoamingEnabled();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForHandlerAction(mDct, 1000);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForHandlerAction(mDct, 1000);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
//user is in roaming
doReturn(true).when(mServiceState).getDataRoaming();
logd("Sending DISABLE_ROAMING_CMD");
mDct.setDataRoamingEnabledByUser(false);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_ROAMING_ON));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// expected tear down all metered DataConnections
verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
any(Message.class));
assertTrue(mDct.isAnyDataConnected());
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING));
// reset roaming settings / data enabled settings at end of this test
mDct.setDataRoamingEnabledByUser(roamingEnabled);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
@Test
@MediumTest
public void testDataCallOnUserDisableRoaming() {
//step 1: mock under roaming service and user disabled roaming from settings.
//step 2: user toggled data settings on
//step 3: only non-metered data call is established
boolean roamingEnabled = mDct.getDataRoamingEnabled();
doReturn(true).when(mServiceState).getDataRoaming();
//set Default and MMS to be metered in the CarrierConfigManager
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
logd("Sending DISABLE_ROAMING_CMD");
mDct.setDataRoamingEnabledByUser(false);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64, 0, 0);
assertTrue(mDct.isAnyDataConnected());
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING));
// reset roaming settings / data enabled settings at end of this test
mDct.setDataRoamingEnabledByUser(roamingEnabled);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
// Test the default data switch scenario.
@FlakyTest /* flakes 1.57% of the time */
@Test
@MediumTest
public void testDDSResetAutoAttach() throws Exception {
mContextFixture.putBooleanResource(
com.android.internal.R.bool.config_auto_attach_data_on_creation, true);
testDataSetup();
assertTrue(mDct.shouldAutoAttach());
mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// The auto attach flag should be reset after update
assertFalse(mDct.shouldAutoAttach());
}
// Test for API carrierActionSetMeteredApnsEnabled.
@FlakyTest
@Ignore
@Test
@MediumTest
public void testCarrierActionSetMeteredApnsEnabled() {
//step 1: setup two DataCalls one for Internet and IMS
//step 2: set data is enabled
//step 3: cold sim is detected
//step 4: all data connection is torn down
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK);
assertTrue(mDct.isAnyDataConnected());
AsyncResult ar = new AsyncResult(null,
new Pair<>(false, DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER), null);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// Validate all metered data connections have been torn down
verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
any(Message.class));
assertTrue(mDct.isAnyDataConnected());
assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
}
private void initApns(String targetApn, String[] canHandleTypes) {
doReturn(targetApn).when(mApnContext).getApnType();
doReturn(ApnSetting.getApnTypesBitmaskFromString(mApnContext.getApnType()))
.when(mApnContext).getApnTypeBitmask();
doReturn(true).when(mApnContext).isConnectable();
ApnSetting apnSetting = createApnSetting(ApnSetting.getApnTypesBitmaskFromString(
TextUtils.join(",", canHandleTypes)));
doReturn(apnSetting).when(mApnContext).getNextApnSetting();
doReturn(apnSetting).when(mApnContext).getApnSetting();
doReturn(mDataConnection).when(mApnContext).getDataConnection();
doReturn(true).when(mApnContext).isEnabled();
doReturn(true).when(mApnContext).isDependencyMet();
doReturn(true).when(mApnContext).isReady();
doReturn(false).when(mApnContext).hasRestrictedRequests(eq(true));
}
// Test the emergency APN setup.
@Test
@SmallTest
public void testTrySetupDataEmergencyApn() {
initApns(ApnSetting.TYPE_EMERGENCY_STRING,
new String[]{ApnSetting.TYPE_EMERGENCY_STRING});
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(),
anyBoolean(), any(Message.class));
}
// Test the XCAP APN setup.
@Test
@SmallTest
public void testTrySetupDataXcapApn() {
initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING});
mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(),
anyBoolean(), any(Message.class));
}
// Test the ENTERPRISE APN setup.
@Test
public void testTrySetupDataEnterpriseApn() {
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<TrafficDescriptor> tdCaptor =
ArgumentCaptor.forClass(TrafficDescriptor.class);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName());
assertEquals(null, tdCaptor.getValue().getOsAppId());
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
SetupDataCallResult result = createSetupDataCallResult();
result.cid = 10;
mSimulatedCommands.setDataCallResult(true, result);
mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
assertEquals(null, tdCaptor.getValue().getDataNetworkName());
assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(),
tdCaptor.getValue().getOsAppId()));
}
// Test the ENTERPRISE APN setup when default data is not set up yet.
@Test
public void testTrySetupDataEnterpriseApnNoDefaultData() {
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<TrafficDescriptor> tdCaptor =
ArgumentCaptor.forClass(TrafficDescriptor.class);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
assertEquals(null, tdCaptor.getValue().getDataNetworkName());
assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(),
tdCaptor.getValue().getOsAppId()));
// Check APN contexts with no DEFAULT set up
Map<Integer, ApnContext> apnContexts = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
assertEquals(DctConstants.State.IDLE, apnContexts.get(ApnSetting.TYPE_DEFAULT).getState());
assertEquals(DctConstants.State.FAILED,
apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState());
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName());
assertEquals(null, tdCaptor.getValue().getOsAppId());
// Check APN contexts after DEFAULT is set up (and ENTERPRISE failure)
apnContexts = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
assertEquals(DctConstants.State.CONNECTED,
apnContexts.get(ApnSetting.TYPE_DEFAULT).getState());
assertEquals(DctConstants.State.FAILED,
apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState());
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
SetupDataCallResult result = createSetupDataCallResult();
result.cid = 10;
mSimulatedCommands.setDataCallResult(true, result);
mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
assertEquals(null, tdCaptor.getValue().getDataNetworkName());
assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(),
tdCaptor.getValue().getOsAppId()));
// Check APN contexts after DEFAULT is set up (and ENTERPRISE reenabled)
apnContexts = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
assertEquals(DctConstants.State.CONNECTED,
apnContexts.get(ApnSetting.TYPE_DEFAULT).getState());
assertEquals(DctConstants.State.CONNECTED,
apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState());
}
// Test the ENTERPRISE APN setup when the same CID is returned.
@Test
public void testTrySetupDataEnterpriseApnDuplicateCid() {
mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask(
NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK);
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
// mSimulatedCommandsVerifier will return the same CID in SetupDataCallResult
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
waitForMs(200);
ArgumentCaptor<TrafficDescriptor> tdCaptor =
ArgumentCaptor.forClass(TrafficDescriptor.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
List<TrafficDescriptor> tds = tdCaptor.getAllValues();
// [0] is default and [1] is enterprise, since default should be set up first
assertEquals(FAKE_APN1, tds.get(0).getDataNetworkName());
assertEquals(null, tds.get(0).getOsAppId());
assertEquals(null, tds.get(1).getDataNetworkName());
assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), tds.get(1).getOsAppId()));
// Check APN contexts after DEFAULT and ENTERPRISE set up
Map<Integer, ApnContext> apnContexts = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
assertEquals(DctConstants.State.CONNECTED,
apnContexts.get(ApnSetting.TYPE_DEFAULT).getState());
assertEquals(DctConstants.State.FAILED,
apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState());
}
@Test
@SmallTest
public void testGetDataConnectionState() {
initApns(ApnSetting.TYPE_SUPL_STRING,
new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_DEFAULT_STRING});
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
// Assert that both APN_TYPE_SUPL & APN_TYPE_DEFAULT are connected even we only setup data
// for APN_TYPE_SUPL
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_SUPL_STRING));
assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING));
}
// Test the unmetered APN setup when data is disabled.
@Test
@SmallTest
public void testTrySetupDataUnmeteredDataDisabled() {
initApns(ApnSetting.TYPE_SUPL_STRING, new String[]{ApnSetting.TYPE_SUPL_STRING});
doReturn(false).when(mDataEnabledSettings).isDataEnabled();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_FOTA_STRING});
mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the unmetered default APN setup when data is disabled. Default APN should always honor
// the users's setting.
@Test
@SmallTest
public void testTrySetupDataUnmeteredDefaultDataDisabled() {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING});
doReturn(false).when(mDataEnabledSettings).isDataEnabled();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
verify(mSimulatedCommandsVerifier, never()).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the metered APN setup when data is disabled.
@Test
@SmallTest
public void testTrySetupMeteredDataDisabled() {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING});
doReturn(false).when(mDataEnabledSettings).isDataEnabled();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the restricted data request when data is disabled.
@Test
@SmallTest
public void testTrySetupRestrictedDataDisabled() {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING});
doReturn(false).when(mDataEnabledSettings).isDataEnabled();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
sendInitializationEvents();
NetworkRequest nr = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build();
mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the restricted data request when roaming is disabled.
@Test
@SmallTest
public void testTrySetupRestrictedRoamingDisabled() {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING});
mDct.setDataRoamingEnabledByUser(false);
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
//user is in roaming
doReturn(true).when(mServiceState).getDataRoaming();
sendInitializationEvents();
NetworkRequest nr = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build();
mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the default data when data is not connectable.
@Test
@SmallTest
public void testTrySetupNotConnectable() {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
doReturn(false).when(mApnContext).isConnectable();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
sendInitializationEvents();
verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the default data on IWLAN.
@Test
@SmallTest
public void testTrySetupDefaultOnIWLAN() {
doReturn(true).when(mTransportManager).isInLegacyMode();
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
sendInitializationEvents();
verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test the default data when the phone is in ECBM.
@Test
@SmallTest
public void testTrySetupDefaultInECBM() {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
doReturn(true).when(mPhone).isInEcm();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
sendInitializationEvents();
verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
// Test update waiting apn list when on data rat change
@FlakyTest /* flakes 0.86% of the time */
@Ignore
@Test
@SmallTest
public void testUpdateWaitingApnListOnDataRatChange() {
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier).setupDataCall(
eq(AccessNetworkType.CDMA2000), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK);
assertTrue(mDct.isAnyDataConnected());
//data rat change from ehrpd to lte
logd("Sending EVENT_DATA_RAT_CHANGED");
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// Verify the disconnected data call due to rat change and retry manger schedule another
// data call setup
verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
any(Message.class));
verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
anyLong(), any(PendingIntent.class));
//Send event for reconnecting data
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
mPhone.getPhoneId(), DcTracker.RELEASE_TYPE_NORMAL, mApnContext));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
assertTrue(mDct.isAnyDataConnected());
}
/**
* Test that fetchDunApns() returns list that prioritize the preferred APN when the preferred
* APN including DUN type.
*/
@Test
public void testFetchDunApnWithPreferredApn() {
// Set support APN types of FAKE_APN1 and FAKE_APN5
mApnSettingContentProvider.setFakeApn1Types("default,dun");
mApnSettingContentProvider.setFakeApn5Types("default,dun");
// Set prefer apn set id.
ContentResolver cr = mContext.getContentResolver();
ContentValues values = new ContentValues();
values.put(Telephony.Carriers.APN_SET_ID, 0);
cr.update(PREFERAPN_URI, values, null, null);
// Set FAKE_APN5 as the preferred APN.
mApnSettingContentProvider.setFakePreferredApn(mApnSettingContentProvider.getFakeApn5());
sendInitializationEvents();
// Return the APN list that set the preferred APN at the top.
ArrayList<ApnSetting> dunApns = mDct.fetchDunApns();
assertEquals(2, dunApns.size());
assertEquals(FAKE_APN5, dunApns.get(0).getApnName());
assertEquals(FAKE_APN1, dunApns.get(1).getApnName());
}
// This tests simulates the race case where the sim status change event is triggered, the
// default data connection is attached, and then the carrier config gets changed which bumps
// the database id which we want to ignore when cleaning up connections and matching against
// the dun APN. Tests b/158908392.
@Test
@SmallTest
public void testCheckForCompatibleDataConnectionWithDunWhenIdsChange() {
//Set dun as a support apn type of FAKE_APN1
mApnSettingContentProvider.setFakeApn1Types("default,supl,dun");
// Enable the default apn
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
//Load the sim and attach the data connection without firing the carrier changed event
final String logMsgPrefix = "testCheckForCompatibleDataConnectionWithDunWhenIdsChange: ";
sendSimStateUpdated(logMsgPrefix);
sendEventDataConnectionAttached(logMsgPrefix);
waitForMs(200);
// Confirm that FAKE_APN1 comes up as a dun candidate
ApnSetting dunApn = mDct.fetchDunApns().get(0);
assertEquals(dunApn.getApnName(), FAKE_APN1);
Map<Integer, ApnContext> apnContexts = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
//Double check that the default apn content is connected while the dun apn context is not
assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(),
DctConstants.State.CONNECTED);
assertNotEquals(apnContexts.get(ApnSetting.TYPE_DUN).getState(),
DctConstants.State.CONNECTED);
//Change the row ids the same way as what happens when we have old apn values in the
//carrier table
mApnSettingContentProvider.setRowIdOffset(100);
sendCarrierConfigChanged(logMsgPrefix);
waitForMs(200);
mDct.enableApn(ApnSetting.TYPE_DUN, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
Map<Integer, ApnContext> apnContextsAfterRowIdsChanged = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
//Make sure that the data connection used earlier wasn't cleaned up and still in use.
assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(),
apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection());
//Check that the DUN is using the same active data connection
assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(),
apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DUN).getDataConnection());
}
@Test
@SmallTest
public void testCheckForCompatibleDataConnectionWithEnterprise() {
// Allow both DEFAULT and ENTERPRISE to use APN 1
mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask(
NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK);
// Enable the DEFAULT APN
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
sendInitializationEvents();
ArgumentCaptor<TrafficDescriptor> tdCaptor =
ArgumentCaptor.forClass(TrafficDescriptor.class);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName());
assertEquals(null, tdCaptor.getValue().getOsAppId());
// Check APN contexts after DEFAULT is set up
Map<Integer, ApnContext> apnContexts = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(),
DctConstants.State.CONNECTED);
assertNotEquals(apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState(),
DctConstants.State.CONNECTED);
// Enable the ENTERPRISE APN
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
SetupDataCallResult result = createSetupDataCallResult();
result.cid = 10;
mSimulatedCommands.setDataCallResult(true, result);
mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
assertEquals(null, tdCaptor.getValue().getDataNetworkName());
assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(),
tdCaptor.getValue().getOsAppId()));
// Check APN contexts after ENTERPRISE is set up
Map<Integer, ApnContext> apnContextsAfterRowIdsChanged = mDct.getApnContexts()
.stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x));
// Make sure that the data connection used earlier wasn't cleaned up and still in use.
assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(),
apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection());
// Check that ENTERPRISE isn't using the same data connection as DEFAULT
assertNotEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(),
apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_ENTERPRISE).getDataConnection());
}
// Test for Data setup with APN Set ID
@Test
@SmallTest
public void testDataSetupWithApnSetId() throws Exception {
// Set the prefer apn set id to "1"
ContentResolver cr = mContext.getContentResolver();
ContentValues values = new ContentValues();
values.put(Telephony.Carriers.APN_SET_ID, 1);
cr.update(PREFERAPN_URI, values, null, null);
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
List<DataProfile> dataProfiles = dpCaptor.getAllValues();
assertEquals(2, dataProfiles.size());
// Verify to use FAKE APN7 which is Default APN with apnSetId=1(Same as the pereferred
// APN's set id).
Optional<DataProfile> fakeApn7 = dataProfiles.stream()
.filter(dp -> dp.getApn().equals(FAKE_APN7)).findFirst();
assertTrue(fakeApn7.isPresent());
verifyDataProfile(fakeApn7.get(), FAKE_APN7, 0, 17, 1, NETWORK_TYPE_LTE_BITMASK);
// Verify to use FAKE APN8 which is IMS APN with apnSetId=-1
// (Telephony.Carriers.MATCH_ALL_APN_SET_ID).
Optional<DataProfile> fakeApn8 = dataProfiles.stream()
.filter(dp -> dp.getApn().equals(FAKE_APN8)).findFirst();
assertTrue(fakeApn8.isPresent());
verifyDataProfile(fakeApn8.get(), FAKE_APN8, 2, 64, 1, NETWORK_TYPE_LTE_BITMASK);
}
// Test oos
@Test
@SmallTest
public void testDataRatChangeOOS() {
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING});
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier).setupDataCall(
eq(AccessNetworkType.CDMA2000), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK);
assertTrue(mDct.isAnyDataConnected());
// Data rat change from ehrpd to unknown due to OOS
logd("Sending EVENT_DATA_RAT_CHANGED");
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UNKNOWN)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// Verify data connection is on
verify(mSimulatedCommandsVerifier, times(0)).deactivateDataCall(
eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
any(Message.class));
// Data rat resume from unknown to ehrpd
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Verify the same data connection
assertEquals(FAKE_APN4, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING));
assertTrue(mDct.isAnyDataConnected());
}
// Test provisioning
/*@Test
@SmallTest
public void testDataEnableInProvisioning() throws Exception {
ContentResolver resolver = mContext.getContentResolver();
assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA));
assertTrue(mDct.isDataEnabled());
assertTrue(mDct.isUserDataEnabled());
mDct.setUserDataEnabled(false);
waitForMs(200);
assertEquals(0, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA));
assertFalse(mDct.isDataEnabled());
assertFalse(mDct.isUserDataEnabled());
// Changing provisioned to 0.
Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null));
waitForMs(200);
assertTrue(mDct.isDataEnabled());
assertTrue(mDct.isUserDataEnabled());
// Enable user data during provisioning. It should write to
// Settings.Global.MOBILE_DATA and keep data enabled when provisioned.
mDct.setUserDataEnabled(true);
Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 1);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null));
waitForMs(200);
assertTrue(mDct.isDataEnabled());
assertTrue(mDct.isUserDataEnabled());
assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA));
}*/
/*
@Test
@SmallTest
public void testNotifyDataEnabledChanged() throws Exception {
doAnswer(invocation -> {
mMessage = (Message) invocation.getArguments()[0];
return true;
}).when(mHandler).sendMessageDelayed(any(), anyLong());
// Test registration.
mDct.registerForDataEnabledChanged(mHandler, DATA_ENABLED_CHANGED, null);
verifyDataEnabledChangedMessage(true, DataEnabledSettings.REASON_REGISTERED);
// Disable user data. Should receive data enabled change to false.
mDct.setUserDataEnabled(false);
waitForMs(200);
verifyDataEnabledChangedMessage(false, DataEnabledSettings.REASON_USER_DATA_ENABLED);
// Changing provisioned to 0. Shouldn't receive any message, as data enabled remains false.
ContentResolver resolver = mContext.getContentResolver();
Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0);
Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
0);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null));
waitForMs(200);
assertFalse(mDct.isDataEnabled());
verify(mHandler, never()).sendMessageDelayed(any(), anyLong());
// Changing provisioningDataEnabled to 1. It should trigger data enabled change to true.
Settings.Global.putInt(resolver,
Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1);
mDct.sendMessage(mDct.obtainMessage(
DctConstants.EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE, null));
waitForMs(200);
verifyDataEnabledChangedMessage(
true, DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED);
}*/
@Test
@SmallTest
public void testNetworkStatusChangedRecoveryOFF() {
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
logd("Sending EVENT_NETWORK_STATUS_CHANGED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
NetworkAgent.VALID_NETWORK, 1, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
logd("Sending EVENT_NETWORK_STATUS_CHANGED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
NetworkAgent.INVALID_NETWORK, 1, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
waitForMs(200);
// Verify that its no-op when the new data stall detection feature is disabled
verify(mSimulatedCommandsVerifier, times(0)).getDataCallList(any(Message.class));
}
@FlakyTest
@Test
@SmallTest
public void testNetworkStatusChangedRecoveryON() {
ContentResolver resolver = mContext.getContentResolver();
Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 0);
doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
logd("Sending EVENT_NETWORK_STATUS_CHANGED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
NetworkAgent.VALID_NETWORK, 1, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
logd("Sending EVENT_NETWORK_STATUS_CHANGED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
NetworkAgent.INVALID_NETWORK, 1, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
verify(mSimulatedCommandsVerifier, times(1)).getDataCallList(any(Message.class));
}
@FlakyTest
@Test
@SmallTest
public void testRecoveryStepPDPReset() {
ContentResolver resolver = mContext.getContentResolver();
Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
Settings.Global.putLong(resolver,
Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 1);
doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
NetworkAgent.INVALID_NETWORK, 1, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
waitForMs(200);
// expected tear down all DataConnections
verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
any(Message.class));
}
@Test
@SmallTest
public void testRecoveryStepReRegister() {
ContentResolver resolver = mContext.getContentResolver();
Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
Settings.Global.putLong(resolver,
Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2);
doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
doReturn(PhoneConstants.State.IDLE).when(mPhone).getState();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
NetworkAgent.INVALID_NETWORK, 1, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// expected to get preferred network type
verify(mSST, times(1)).reRegisterNetwork(eq(null));
}
@Test
@SmallTest
public void testRecoveryStepRestartRadio() {
ContentResolver resolver = mContext.getContentResolver();
Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
Settings.Global.putLong(resolver,
Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3);
doReturn(new SignalStrength()).when(mPhone).getSignalStrength();
doReturn(PhoneConstants.State.IDLE).when(mPhone).getState();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING});
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
NetworkAgent.INVALID_NETWORK, 1, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// expected to get preferred network type
verify(mSST, times(1)).powerOffRadioSafely();
}
private void verifyDataEnabledChangedMessage(boolean enabled, int reason) {
verify(mHandler, times(1)).sendMessageDelayed(any(), anyLong());
Pair<Boolean, Integer> result = (Pair) ((AsyncResult) mMessage.obj).result;
assertEquals(DATA_ENABLED_CHANGED, mMessage.what);
assertEquals(enabled, result.first);
assertEquals(reason, (int) result.second);
clearInvocations(mHandler);
}
private void setUpSubscriptionPlans(boolean isNrUnmetered) throws Exception {
List<SubscriptionPlan> plans = new ArrayList<>();
if (isNrUnmetered) {
plans.add(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());
}
plans.add(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());
replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans);
doReturn(plans.toArray(new SubscriptionPlan[0])).when(mNetworkPolicyManager)
.getSubscriptionPlans(anyInt(), any());
}
private void resetSubscriptionPlans() throws Exception {
replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, null);
}
private void setUpSubscriptionOverride(int[] networkTypes, boolean isUnmetered)
throws Exception {
List<Integer> networkTypesList = null;
if (networkTypes != null) {
networkTypesList = new ArrayList<>();
for (int networkType : networkTypes) {
networkTypesList.add(networkType);
}
}
replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, networkTypesList);
replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, isUnmetered);
}
private void resetSubscriptionOverride() throws Exception {
replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, null);
replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, false);
}
private boolean isNetworkTypeUnmetered(int networkType) throws Exception {
Method method = DcTracker.class.getDeclaredMethod(
"isNetworkTypeUnmetered", int.class);
method.setAccessible(true);
return (boolean) method.invoke(mDct, networkType);
}
private int setUpDataConnection() throws Exception {
Field dc = DcTracker.class.getDeclaredField("mDataConnections");
dc.setAccessible(true);
Field uig = DcTracker.class.getDeclaredField("mUniqueIdGenerator");
uig.setAccessible(true);
int id = ((AtomicInteger) uig.get(mDct)).getAndIncrement();
((HashMap<Integer, DataConnection>) dc.get(mDct)).put(id, mDataConnection);
return id;
}
private void resetDataConnection(int id) throws Exception {
Field dc = DcTracker.class.getDeclaredField("mDataConnections");
dc.setAccessible(true);
((HashMap<Integer, DataConnection>) dc.get(mDct)).remove(id);
}
private void setUpWatchdogTimer() {
// Watchdog active for 10s
mBundle.putLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG, 10000);
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId());
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
mContext.sendBroadcast(intent);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
private boolean getWatchdogStatus() throws Exception {
Field field = DcTracker.class.getDeclaredField(("mWatchdog"));
field.setAccessible(true);
return (boolean) field.get(mDct);
}
private Map<Integer, List<Message>> getHandoverCompletionMessages() throws Exception {
Field field = DcTracker.class.getDeclaredField(("mHandoverCompletionMsgs"));
field.setAccessible(true);
return (Map<Integer, List<Message>>) field.get(mDct);
}
private void setUpTempNotMetered() {
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR)
.when(mPhone).getRadioAccessFamily();
doReturn(1).when(mPhone).getSubId();
mBundle.putBoolean(CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true);
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId());
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
mContext.sendBroadcast(intent);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
@Test
public void testIsNetworkTypeUnmetered() throws Exception {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
// only 5G unmetered
setUpSubscriptionOverride(new int[]{TelephonyManager.NETWORK_TYPE_NR}, true);
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
// all network types metered
setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), false);
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
// all network types unmetered
setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), true);
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
resetSubscriptionOverride();
}
@Test
public void testIsNetworkTypeUnmeteredViaSubscriptionPlans() throws Exception {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
// only 5G unmetered
setUpSubscriptionPlans(true);
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
// all network types metered
setUpSubscriptionPlans(false);
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
// all network types unmetered
List<SubscriptionPlan> plans = new ArrayList<>();
plans.add(SubscriptionPlan.Builder
.createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"),
Period.ofMonths(1))
.setDataLimit(SubscriptionPlan.BYTES_UNLIMITED,
SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
.build());
replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans);
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR));
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE));
assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN));
resetSubscriptionPlans();
}
@Test
public void testIsNrUnmeteredSubscriptionPlans() throws Exception {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
int id = setUpDataConnection();
setUpSubscriptionPlans(false);
setUpWatchdogTimer();
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
setUpTempNotMetered();
clearInvocations(mDataConnection);
// NetCapability should be metered when connected to 5G with no unmetered plan or frequency
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(false);
// Set SubscriptionPlans unmetered
setUpSubscriptionPlans(true);
// NetCapability should switch to unmetered with an unmetered plan
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(true);
// Set MMWAVE frequency to unmetered
mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true);
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId());
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
mContext.sendBroadcast(intent);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
clearInvocations(mDataConnection);
// NetCapability should switch to metered without fr=MMWAVE
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(false);
// NetCapability should switch to unmetered with fr=MMWAVE
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(true);
resetDataConnection(id);
resetSubscriptionPlans();
}
@Test
public void testIsNrUnmeteredCarrierConfigs() throws Exception {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
int id = setUpDataConnection();
setUpSubscriptionPlans(false);
setUpWatchdogTimer();
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
setUpTempNotMetered();
clearInvocations(mDataConnection);
// NetCapability should be metered when connected to 5G with no unmetered plan or frequency
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(false);
// Set MMWAVE frequency to unmetered
mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL, true);
mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true);
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId());
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
mContext.sendBroadcast(intent);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
clearInvocations(mDataConnection);
// NetCapability should switch to unmetered when fr=MMWAVE and MMWAVE unmetered
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(true);
// NetCapability should switch to metered when fr=SUB6 and MMWAVE unmetered
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(false);
// Set SUB6 frequency to unmetered
doReturn(2).when(mPhone).getSubId();
mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false);
mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL, true);
intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId());
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
mContext.sendBroadcast(intent);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
clearInvocations(mDataConnection);
// NetCapability should switch to unmetered when fr=SUB6 and SUB6 unmetered
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
verify(mDataConnection, times(1)).onMeterednessChanged(true);
resetDataConnection(id);
resetSubscriptionPlans();
}
@Test
public void testReevaluateUnmeteredConnectionsOnNetworkChange() throws Exception {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
int id = setUpDataConnection();
setUpSubscriptionPlans(true);
setUpWatchdogTimer();
setUpTempNotMetered();
clearInvocations(mDataConnection);
// NetCapability should be unmetered when connected to 5G
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection, times(1)).onMeterednessChanged(true);
// NetCapability should be metered when disconnected from 5G
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
verify(mDataConnection, times(1)).onMeterednessChanged(false);
resetDataConnection(id);
resetSubscriptionPlans();
}
@Test
public void testReevaluateUnmeteredConnectionsOnWatchdog() throws Exception {
initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING});
int id = setUpDataConnection();
setUpSubscriptionPlans(true);
setUpWatchdogTimer();
// Watchdog inactive when unmetered and not connected to 5G
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
assertFalse(getWatchdogStatus());
// Watchdog active when unmetered and connected to 5G
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
assertTrue(getWatchdogStatus());
// Watchdog inactive when metered
setUpSubscriptionPlans(false);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
assertFalse(getWatchdogStatus());
resetDataConnection(id);
resetSubscriptionPlans();
}
/**
* Test if this is a path prefix match against the given Uri. Verifies that
* scheme, authority, and atomic path segments match.
*
* Copied from frameworks/base/core/java/android/net/Uri.java
*/
private boolean isPathPrefixMatch(Uri uriA, Uri uriB) {
if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false;
if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false;
List<String> segA = uriA.getPathSegments();
List<String> segB = uriB.getPathSegments();
final int size = segB.size();
if (segA.size() < size) return false;
for (int i = 0; i < size; i++) {
if (!Objects.equals(segA.get(i), segB.get(i))) {
return false;
}
}
return true;
}
@Test
public void testNoApnContextsWhenDataIsDisabled() throws java.lang.InterruptedException {
//Check that apn contexts are loaded.
assertTrue(mDct.getApnContexts().size() > 0);
//Do work normally done in teardown.
mDct.removeCallbacksAndMessages(null);
mDcTrackerTestHandler.quit();
mDcTrackerTestHandler.join();
//Set isDataCapable to false for the new DcTracker being created in DcTrackerTestHandler.
doReturn(false).when(mTelephonyManager).isDataCapable();
mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName());
setReady(false);
mDcTrackerTestHandler.start();
waitUntilReady();
assertEquals(0, mDct.getApnContexts().size());
//No need to clean up handler because that work is done in teardown.
}
@Test
public void testRatChanged() throws Exception {
DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
boolean allowed = mDct.isDataAllowed(dataConnectionReasons);
assertFalse(dataConnectionReasons.toString(), allowed);
logd("Sending EVENT_ENABLE_APN");
// APN id 0 is APN_TYPE_DEFAULT
mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
dataConnectionReasons = new DataConnectionReasons();
allowed = mDct.isDataAllowed(dataConnectionReasons);
assertTrue(dataConnectionReasons.toString(), allowed);
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
eq(AccessNetworkType.EUTRAN), dpCaptor.capture(),
eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK);
verifyDataConnected(FAKE_APN1);
doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS).when(mServiceState)
.getRilDataRadioTechnology();
logd("Sending EVENT_DATA_RAT_CHANGED");
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.build();
doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
anyInt(), anyInt());
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Data connection is running on a different thread. Have to wait.
waitForMs(200);
// expected tear down all metered DataConnections
verify(mSimulatedCommandsVerifier).deactivateDataCall(
eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
any(Message.class));
}
@Test
public void testApnConfigRepositoryUpdatedOnCarrierConfigChange() {
assertPriority(ApnSetting.TYPE_CBS_STRING, 2);
assertPriority(ApnSetting.TYPE_MMS_STRING, 2);
mBundle.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY,
new String[] {
ApnSetting.TYPE_CBS_STRING + ":11",
ApnSetting.TYPE_MMS_STRING + ":19",
});
sendInitializationEvents();
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId());
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId());
mContext.sendBroadcast(intent);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
assertPriority(ApnSetting.TYPE_CBS_STRING, 11);
assertPriority(ApnSetting.TYPE_MMS_STRING, 19);
//Ensure apns are in sorted order.
ApnContext lastApnContext = null;
for (ApnContext apnContext : mDct.getApnContexts()) {
if (lastApnContext != null) {
assertTrue(apnContext.getPriority() <= lastApnContext.getPriority());
}
lastApnContext = apnContext;
}
}
private void assertPriority(String type, int priority) {
assertEquals(priority, mDct.getApnContexts().stream()
.filter(x -> x.getApnType().equals(type))
.findFirst().get().getPriority());
}
@Test
public void testProvisionBroadcastReceiver() {
Intent intent = new Intent("com.android.internal.telephony.PROVISION");
intent.putExtra("provision.phone.id", mPhone.getPhoneId());
try {
mContext.sendBroadcast(intent);
} catch (SecurityException e) {
fail();
}
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
}
@Test
public void testRetryHandoverWhenDisconnecting() throws Exception {
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
setUpDataConnection();
SparseArray<ApnContext> apnContextsByType = Mockito.mock(SparseArray.class);
ConcurrentHashMap<String, ApnContext> apnContexts = Mockito.mock(ConcurrentHashMap.class);
doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS));
doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING));
doReturn(false).when(mApnContext).isConnectable();
doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt());
doReturn(DctConstants.State.DISCONNECTING).when(mApnContext).getState();
replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType);
replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts);
sendInitializationEvents();
logd("Sending EVENT_ENABLE_APN");
// APN id 0 is APN_TYPE_DEFAULT
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER,
mDct.obtainMessage(12345));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
assertTrue(isHandoverPending(ApnSetting.TYPE_IMS));
// Verify no handover request was sent
verify(mDataConnection, never()).bringUp(any(ApnContext.class), anyInt(), anyInt(),
any(Message.class), anyInt(), anyInt(), anyInt(), anyBoolean());
doReturn(DctConstants.State.RETRYING).when(mApnContext).getState();
// Data now is disconnected
doReturn(true).when(mApnContext).isConnectable();
doReturn(true).when(mDataEnabledSettings).isDataEnabled(anyInt());
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE,
new AsyncResult(Pair.create(mApnContext, 0), null, null)));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataConnection).bringUp(any(ApnContext.class), anyInt(), anyInt(),
any(Message.class), anyInt(), eq(DcTracker.REQUEST_TYPE_HANDOVER), anyInt(),
anyBoolean());
}
@Test
public void testDataUnthrottled() throws Exception {
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler);
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_UNTHROTTLED,
new AsyncResult(null, FAKE_APN3, null)));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
verify(mDataThrottler).setRetryTime(
eq(ApnSetting.TYPE_IMS),
eq(RetryManager.NO_SUGGESTED_RETRY_DELAY),
eq(DcTracker.REQUEST_TYPE_NORMAL));
}
@Test
public void testDataUnthrottledAfterAPNChanged() throws Exception {
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler);
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_CHANGED, null));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Verify unthrottling
verify(mDataThrottler, times(2)).reset();
}
@Test
public void testDataUnthrottledOnSimStateChanged() throws Exception {
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler);
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
sendSimStateUpdated("testDataUnthrottledOnSimStateChanged");
// Verify unthrottling
verify(mDataThrottler, times(2)).reset();
}
@Test
public void testHandlingSecondHandoverRequest() throws Exception {
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
setUpDataConnection();
SparseArray<ApnContext> apnContextsByType = Mockito.mock(SparseArray.class);
ConcurrentHashMap<String, ApnContext> apnContexts = Mockito.mock(ConcurrentHashMap.class);
doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS));
doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING));
doReturn(false).when(mApnContext).isConnectable();
doReturn(DctConstants.State.CONNECTING).when(mApnContext).getState();
replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType);
replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts);
sendInitializationEvents();
logd("Sending EVENT_ENABLE_APN");
// APN id 0 is APN_TYPE_DEFAULT
Message msg = mDct.obtainMessage(12345);
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, msg);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
Map<Integer, List<Message>> msgs = getHandoverCompletionMessages();
// Make sure the messages was queued properly instead of fired right away.
assertTrue(msgs.get(ApnSetting.TYPE_IMS).contains(msg));
}
@Test
public void testDataThrottledNotAllowData() throws Exception {
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler);
doReturn(SystemClock.elapsedRealtime() + 100000).when(mDataThrottler)
.getRetryTime(ApnSetting.TYPE_IMS);
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
sendInitializationEvents();
DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
boolean allowed = mDct.isDataAllowed(mApnContext, DcTracker.REQUEST_TYPE_NORMAL,
dataConnectionReasons);
assertFalse(dataConnectionReasons.toString(), allowed);
assertTrue(dataConnectionReasons.contains(DataDisallowedReasonType.DATA_THROTTLED));
// Makre sure no data setup request
verify(mSimulatedCommandsVerifier, never()).setupDataCall(
anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(),
anyInt(), any(), any(), anyBoolean(), any(Message.class));
}
@Test
public void testNotifyDataDisconnected() {
// Verify notify data disconnected on DCT constructor, initialized in setUp()
ArgumentCaptor<PreciseDataConnectionState> captor =
ArgumentCaptor.forClass(PreciseDataConnectionState.class);
verify(mPhone, times(13)).notifyDataConnection(captor.capture());
for (PreciseDataConnectionState state : captor.getAllValues()) {
assertEquals(TelephonyManager.DATA_DISCONNECTED, state.getState());
}
}
/**
* There is a corresponding test {@link DataConnectionTest#testDataServiceTempUnavailable()} to
* test DataConnection behavior.
*/
@Test
public void testDataServiceTempUnavailable() {
Handler handler = Mockito.mock(Handler.class);
Message handoverCompleteMessage = Message.obtain(handler);
addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS);
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_SETUP_COMPLETE,
DcTracker.REQUEST_TYPE_HANDOVER, DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN,
new AsyncResult(Pair.create(mApnContext, 0),
DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE, new Exception())));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Ensure handover is not completed yet
verify(handler, never()).sendMessageDelayed(any(), anyLong());
}
@Test
public void testNormalRequestDoesNotFailHandoverRequest() {
Handler handler = Mockito.mock(Handler.class);
Message handoverCompleteMessage = Message.obtain(handler);
addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS);
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
// Ensure handover is not completed yet
verify(handler, never()).sendMessageDelayed(any(), anyLong());
}
@Test
public void testPreferenceChangedFallback() {
Handler handler = Mockito.mock(Handler.class);
doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mTransportManager)
.getPreferredTransport(anyInt());
Message handoverCompleteMessage = Message.obtain(handler);
addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS);
initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING});
mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER,
handoverCompleteMessage);
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
Bundle bundle = handoverCompleteMessage.getData();
assertTrue(bundle.getBoolean("extra_handover_failure_fallback"));
}
}