blob: d756f7602ec4bf4ca5289ee28885994352cbc707 [file] [log] [blame]
/*
* Copyright (C) 2006 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 android.net.NetworkFactory.CMD_CANCEL_REQUEST;
import static android.net.NetworkFactory.CMD_REQUEST_NETWORK;
import static com.android.internal.telephony.dataconnection.TelephonyNetworkFactory.EVENT_ACTIVE_PHONE_SWITCH;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.StringNetworkSpecifier;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
import android.telephony.AccessNetworkConstants;
import com.android.telephony.Rlog;
import android.telephony.data.ApnSetting;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.FlakyTest;
import com.android.internal.telephony.PhoneSwitcher;
import com.android.internal.telephony.RadioConfig;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams;
import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams.HandoverCallback;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import java.lang.reflect.Field;
import java.util.ArrayList;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class TelephonyNetworkFactoryTest extends TelephonyTest {
private final static String LOG_TAG = "TelephonyNetworkFactoryTest";
@Mock
PhoneSwitcher mPhoneSwitcher;
@Mock
private RadioConfig mMockRadioConfig;
@Mock
private DataConnection mDataConnection;
private String mTestName = "";
private final ArrayList<NetworkRequest> mNetworkRequestList = new ArrayList<>();
private TelephonyNetworkFactory mTelephonyNetworkFactoryUT;
private int mRequestId = 0;
private void log(String str) {
Rlog.d(LOG_TAG + " " + mTestName, str);
}
private NetworkRequest makeSubSpecificInternetRequest(int subId) {
NetworkCapabilities netCap = (new NetworkCapabilities()).
addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
NetworkRequest networkRequest = new NetworkRequest(netCap, -1,
mRequestId++, NetworkRequest.Type.REQUEST);
mTelephonyNetworkFactoryUT.obtainMessage(CMD_REQUEST_NETWORK, 0, 0, networkRequest)
.sendToTarget();
return networkRequest;
}
private NetworkRequest makeDefaultInternetRequest() {
NetworkCapabilities netCap = (new NetworkCapabilities())
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
NetworkRequest networkRequest = new NetworkRequest(netCap, -1,
mRequestId++, NetworkRequest.Type.REQUEST);
mTelephonyNetworkFactoryUT.obtainMessage(CMD_REQUEST_NETWORK, 0, 0, networkRequest)
.sendToTarget();
return networkRequest;
}
private NetworkRequest makeSubSpecificMmsRequest(int subId) {
NetworkCapabilities netCap = (new NetworkCapabilities()).
addCapability(NetworkCapabilities.NET_CAPABILITY_MMS).
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
NetworkRequest networkRequest = new NetworkRequest(netCap, -1,
mRequestId++, NetworkRequest.Type.REQUEST);
mTelephonyNetworkFactoryUT.obtainMessage(CMD_REQUEST_NETWORK, 0, 0, networkRequest)
.sendToTarget();
return networkRequest;
}
private void releaseNetworkRequest(NetworkRequest networkRequest) {
mTelephonyNetworkFactoryUT.obtainMessage(CMD_CANCEL_REQUEST, 0, 0, networkRequest)
.sendToTarget();
}
private void activatePhoneInPhoneSwitcher(int phoneId, boolean active) {
doReturn(active).when(mPhoneSwitcher).shouldApplyNetworkRequest(any(), eq(phoneId));
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(EVENT_ACTIVE_PHONE_SWITCH);
}
private void activatePhoneInPhoneSwitcher(int phoneId, NetworkRequest nr, boolean active) {
doReturn(active).when(mPhoneSwitcher).shouldApplyNetworkRequest(eq(nr), eq(phoneId));
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(EVENT_ACTIVE_PHONE_SWITCH);
}
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
replaceInstance(RadioConfig.class, "sRadioConfig", null, mMockRadioConfig);
mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
new String[]{"wifi,1,1,1,-1,true", "mobile,0,0,0,-1,true",
"mobile_mms,2,0,2,60000,true", "mobile_supl,3,0,2,60000,true",
"mobile_dun,4,0,2,60000,true", "mobile_hipri,5,0,3,60000,true",
"mobile_fota,10,0,2,60000,true", "mobile_ims,11,0,2,60000,true",
"mobile_cbs,12,0,2,60000,true", "wifi_p2p,13,1,0,-1,true",
"mobile_ia,14,0,2,-1,true", "mobile_emergency,15,0,2,-1,true"});
doAnswer(invocation -> {
mNetworkRequestList.add((NetworkRequest) invocation.getArguments()[0]);
return null;
}).when(mDcTracker).requestNetwork(any(), anyInt(), any());
doAnswer(invocation -> {
mNetworkRequestList.remove((NetworkRequest) invocation.getArguments()[0]);
return null;
}).when(mDcTracker).releaseNetwork(any(), anyInt());
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
private void createMockedTelephonyComponents() throws Exception {
replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcher);
mTelephonyNetworkFactoryUT = new TelephonyNetworkFactory(Looper.myLooper(), mPhone);
verify(mConnectivityManager).registerNetworkFactory(any(), anyString());
verify(mPhoneSwitcher).registerForActivePhoneSwitch(any(), anyInt(), any());
}
/**
* Test that phone active changes cause the DcTracker to get poked.
*/
@FlakyTest
@Test
@SmallTest
public void testActive() throws Exception {
mTestName = "testActive";
final int phoneId = 0;
final int subId = 0;
createMockedTelephonyComponents();
doReturn(false).when(mPhoneSwitcher).shouldApplyNetworkRequest(any(), anyInt());
doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
// fake onSubscriptionChangedListener being triggered.
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
log("addDefaultRequest");
makeDefaultInternetRequest();
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
log("setPhoneActive true: phoneId = " + phoneId);
activatePhoneInPhoneSwitcher(phoneId, true);
processAllMessages();
assertEquals(1, mNetworkRequestList.size());
log("makeSubSpecificInternetRequest: subId = " + subId);
NetworkRequest subSpecificDefault = makeSubSpecificInternetRequest(subId);
processAllMessages();
assertEquals(2, mNetworkRequestList.size());
log("setPhoneActive false: phoneId = " + phoneId);
activatePhoneInPhoneSwitcher(phoneId, false);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
log("makeSubSpecificInternetRequest: subId = " + subId);
NetworkRequest subSpecificMms = makeSubSpecificMmsRequest(subId);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
log("setPhoneActive true: phoneId = " + phoneId);
activatePhoneInPhoneSwitcher(phoneId, true);
processAllMessages();
assertEquals(3, mNetworkRequestList.size());
log("releaseNetworkRequest: subSpecificDefault = " + subSpecificDefault);
releaseNetworkRequest(subSpecificDefault);
processAllMessages();
assertEquals(2, mNetworkRequestList.size());
log("setPhoneActive false: phoneId = " + phoneId);
activatePhoneInPhoneSwitcher(phoneId, false);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
log("releaseNetworkRequest: subSpecificMms = " + subSpecificMms);
releaseNetworkRequest(subSpecificMms);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
log("setPhoneActive true: phoneId = " + phoneId);
activatePhoneInPhoneSwitcher(phoneId, true);
processAllMessages();
assertEquals(1, mNetworkRequestList.size());
}
/**
* Test that network request changes cause the DcTracker to get poked.
*/
@Test
@SmallTest
public void testRequests() throws Exception {
mTestName = "testActive";
final int numberOfPhones = 2;
final int phoneId = 0;
final int altPhoneId = 1;
final int subId = 0;
final int altSubId = 1;
final int unusedSubId = 2;
createMockedTelephonyComponents();
doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
activatePhoneInPhoneSwitcher(phoneId, true);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
makeDefaultInternetRequest();
processAllMessages();
assertEquals(1, mNetworkRequestList.size());
doReturn(altSubId).when(mSubscriptionController).getSubIdUsingPhoneId(altPhoneId);
processAllMessages();
assertEquals(1, mNetworkRequestList.size());
activatePhoneInPhoneSwitcher(phoneId, false);
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(EVENT_ACTIVE_PHONE_SWITCH);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
NetworkRequest subSpecificMmsRequest = makeSubSpecificMmsRequest(subId);
activatePhoneInPhoneSwitcher(phoneId, subSpecificMmsRequest, true);
processAllMessages();
assertEquals(1, mNetworkRequestList.size());
doReturn(unusedSubId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
makeSubSpecificInternetRequest(subId);
processAllMessages();
assertEquals(0, mNetworkRequestList.size());
doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId);
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
processAllMessages();
activatePhoneInPhoneSwitcher(phoneId, true);
processAllMessages();
assertEquals(3, mNetworkRequestList.size());
}
/**
* Test handover when there is no live data connection
*/
@Test
@SmallTest
public void testHandoverNoLiveData() throws Exception {
createMockedTelephonyComponents();
doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0);
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
activatePhoneInPhoneSwitcher(0, true);
makeDefaultInternetRequest();
makeSubSpecificMmsRequest(0);
processAllMessages();
Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler");
f.setAccessible(true);
Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT);
HandoverCallback handoverCallback = mock(HandoverCallback.class);
HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS,
AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback);
AsyncResult ar = new AsyncResult(null, hp, null);
h.sendMessage(h.obtainMessage(5, ar));
processAllMessages();
doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mTransportManager)
.getCurrentTransport(anyInt());
hp = new HandoverParams(ApnSetting.TYPE_MMS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
handoverCallback);
ar = new AsyncResult(null, hp, null);
h.sendMessage(h.obtainMessage(5, ar));
processAllMessages();
}
/**
* Test handover when the data connection is being connected.
*/
@Test
@SmallTest
public void testHandoverActivatingData() throws Exception {
createMockedTelephonyComponents();
doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0);
mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED);
activatePhoneInPhoneSwitcher(0, true);
makeDefaultInternetRequest();
makeSubSpecificMmsRequest(0);
processAllMessages();
Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler");
f.setAccessible(true);
Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT);
HandoverCallback handoverCallback = mock(HandoverCallback.class);
Mockito.reset(mDcTracker);
doReturn(mDataConnection).when(mDcTracker).getDataConnectionByApnType(anyString());
doReturn(false).when(mDataConnection).isActive();
HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS,
AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback);
AsyncResult ar = new AsyncResult(null, hp, null);
h.sendMessage(h.obtainMessage(5, ar));
processAllMessages();
verify(mDcTracker, times(1)).releaseNetwork(any(), eq(1));
verify(mDcTracker, times(1)).requestNetwork(any(), eq(1), any());
}
}