Remove usage of networkAttributes

networkAttributes is a legacy configuration that is now only used to
configure which legacy type networks are supported, and what the restore
timer is for that network type, for the deprecated
startUsingNetworkFeature API.

Use a dedicated resource for the restore timers, and build supported
legacy network types using hasSystemFeature for wifi, wifi p2p,
bluetooth, proxy types, and TelephonyManager.isDataCapable for the
mobile types.

Bug: 146206136
Test: atest FrameworksNetTests
Change-Id: I3a771d3de6c5e912f18d2834e3a50af797ac4991
This commit is contained in:
Remi NGUYEN VAN
2021-03-09 13:35:25 +09:00
parent 98de10a7a1
commit 9f9922813f
5 changed files with 218 additions and 105 deletions

View File

@@ -42,4 +42,14 @@
-->
</string-array>
<string-array translatable="false" name="config_legacy_networktype_restore_timers">
<item>2,60000</item><!-- mobile_mms -->
<item>3,60000</item><!-- mobile_supl -->
<item>4,60000</item><!-- mobile_dun -->
<item>5,60000</item><!-- mobile_hipri -->
<item>10,60000</item><!-- mobile_fota -->
<item>11,60000</item><!-- mobile_ims -->
<item>12,60000</item><!-- mobile_cbs -->
</string-array>
</resources>

View File

@@ -17,11 +17,11 @@
<overlayable name="ServiceConnectivityResourcesConfig">
<policy type="product|system|vendor">
<!-- Configuration values for ConnectivityService -->
<item type="array" name="config_legacy_networktype_restore_timers"/>
<item type="string" name="config_networkCaptivePortalServerUrl"/>
<item type="integer" name="config_networkTransitionTimeout"/>
<item type="array" name="config_wakeonlan_supported_interfaces"/>
</policy>
</overlayable>
</resources>

View File

@@ -17,6 +17,10 @@
package com.android.server;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.FEATURE_WIFI;
import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
@@ -28,9 +32,23 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
@@ -110,7 +128,6 @@ import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMonitorManager;
@@ -617,11 +634,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private UserManager mUserManager;
private NetworkConfig[] mNetConfigs;
private int mNetworksDefined;
// the set of network types that can only be enabled by system/sig apps
private List mProtectedNetworks;
private List<Integer> mProtectedNetworks;
private Set<String> mWolSupportedInterfaces;
@@ -711,18 +725,63 @@ public class ConnectivityService extends IConnectivityManager.Stub
* They are therefore not thread-safe with respect to each other.
* - getNetworkForType() can be called at any time on binder threads. It is synchronized
* on mTypeLists to be thread-safe with respect to a concurrent remove call.
* - getRestoreTimerForType(type) is also synchronized on mTypeLists.
* - dump is thread-safe with respect to concurrent add and remove calls.
*/
private final ArrayList<NetworkAgentInfo> mTypeLists[];
@NonNull
private final ConnectivityService mService;
// Restore timers for requestNetworkForFeature (network type -> timer in ms). Types without
// an entry have no timer (equivalent to -1). Lazily loaded.
@NonNull
private ArrayMap<Integer, Integer> mRestoreTimers = new ArrayMap<>();
LegacyTypeTracker(@NonNull ConnectivityService service) {
mService = service;
mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
}
public void addSupportedType(int type) {
public void loadSupportedTypes(@NonNull Context ctx, @NonNull TelephonyManager tm) {
final PackageManager pm = ctx.getPackageManager();
if (pm.hasSystemFeature(FEATURE_WIFI)) {
addSupportedType(TYPE_WIFI);
}
if (pm.hasSystemFeature(FEATURE_WIFI_DIRECT)) {
addSupportedType(TYPE_WIFI_P2P);
}
if (tm.isDataCapable()) {
// Telephony does not have granular support for these types: they are either all
// supported, or none is supported
addSupportedType(TYPE_MOBILE);
addSupportedType(TYPE_MOBILE_MMS);
addSupportedType(TYPE_MOBILE_SUPL);
addSupportedType(TYPE_MOBILE_DUN);
addSupportedType(TYPE_MOBILE_HIPRI);
addSupportedType(TYPE_MOBILE_FOTA);
addSupportedType(TYPE_MOBILE_IMS);
addSupportedType(TYPE_MOBILE_CBS);
addSupportedType(TYPE_MOBILE_IA);
addSupportedType(TYPE_MOBILE_EMERGENCY);
}
if (pm.hasSystemFeature(FEATURE_BLUETOOTH)) {
addSupportedType(TYPE_BLUETOOTH);
}
if (pm.hasSystemFeature(FEATURE_WATCH)) {
// TYPE_PROXY is only used on Wear
addSupportedType(TYPE_PROXY);
}
// Ethernet is often not specified in the configs, although many devices can use it via
// USB host adapters. Add it as long as the ethernet service is here.
if (ctx.getSystemService(Context.ETHERNET_SERVICE) != null) {
addSupportedType(TYPE_ETHERNET);
}
// Always add TYPE_VPN as a supported type
addSupportedType(TYPE_VPN);
}
private void addSupportedType(int type) {
if (mTypeLists[type] != null) {
throw new IllegalStateException(
"legacy list for type " + type + "already initialized");
@@ -743,6 +802,35 @@ public class ConnectivityService extends IConnectivityManager.Stub
return null;
}
public int getRestoreTimerForType(int type) {
synchronized (mTypeLists) {
if (mRestoreTimers == null) {
mRestoreTimers = loadRestoreTimers();
}
return mRestoreTimers.getOrDefault(type, -1);
}
}
private ArrayMap<Integer, Integer> loadRestoreTimers() {
final String[] configs = mService.mResources.get().getStringArray(
com.android.connectivity.resources.R.array
.config_legacy_networktype_restore_timers);
final ArrayMap<Integer, Integer> ret = new ArrayMap<>(configs.length);
for (final String config : configs) {
final String[] splits = TextUtils.split(config, ",");
if (splits.length != 2) {
logwtf("Invalid restore timer token count: " + config);
continue;
}
try {
ret.put(Integer.parseInt(splits[0]), Integer.parseInt(splits[1]));
} catch (NumberFormatException e) {
logwtf("Invalid restore timer number format: " + config, e);
}
}
return ret;
}
private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
boolean isDefaultNetwork) {
if (DBG) {
@@ -1165,64 +1253,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
// TODO: What is the "correct" way to do determine if this is a wifi only device?
boolean wifiOnly = mSystemProperties.getBoolean("ro.radio.noril", false);
log("wifiOnly=" + wifiOnly);
String[] naStrings = context.getResources().getStringArray(
com.android.internal.R.array.networkAttributes);
for (String naString : naStrings) {
try {
NetworkConfig n = new NetworkConfig(naString);
if (VDBG) log("naString=" + naString + " config=" + n);
if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
loge("Error in networkAttributes - ignoring attempt to define type " +
n.type);
continue;
}
if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
log("networkAttributes - ignoring mobile as this dev is wifiOnly " +
n.type);
continue;
}
if (mNetConfigs[n.type] != null) {
loge("Error in networkAttributes - ignoring attempt to redefine type " +
n.type);
continue;
}
mLegacyTypeTracker.addSupportedType(n.type);
mNetConfigs[n.type] = n;
mNetworksDefined++;
} catch(Exception e) {
// ignore it - leave the entry null
}
}
// Forcibly add TYPE_VPN as a supported type, if it has not already been added via config.
if (mNetConfigs[TYPE_VPN] == null) {
// mNetConfigs is used only for "restore time", which isn't applicable to VPNs, so we
// don't need to add TYPE_VPN to mNetConfigs.
mLegacyTypeTracker.addSupportedType(TYPE_VPN);
mNetworksDefined++; // used only in the log() statement below.
}
// Do the same for Ethernet, since it's often not specified in the configs, although many
// devices can use it via USB host adapters.
if (mNetConfigs[TYPE_ETHERNET] == null
&& mContext.getSystemService(Context.ETHERNET_SERVICE) != null) {
mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
mNetworksDefined++;
}
if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
mProtectedNetworks = new ArrayList<Integer>();
mLegacyTypeTracker.loadSupportedTypes(mContext, mTelephonyManager);
mProtectedNetworks = new ArrayList<>();
int[] protectedNetworks = context.getResources().getIntArray(
com.android.internal.R.array.config_protectedNetworks);
for (int p : protectedNetworks) {
if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
if (mLegacyTypeTracker.isTypeSupported(p) && !mProtectedNetworks.contains(p)) {
mProtectedNetworks.add(p);
} else {
if (DBG) loge("Ignoring protectedNetwork " + p);
@@ -2626,9 +2662,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if the system property isn't set, use the value for the apn type
int ret = RESTORE_DEFAULT_NETWORK_DELAY;
if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
(mNetConfigs[networkType] != null)) {
ret = mNetConfigs[networkType].restoreTime;
if (mLegacyTypeTracker.isTypeSupported(networkType)) {
ret = mLegacyTypeTracker.getRestoreTimerForType(networkType);
}
return ret;
}
@@ -4835,6 +4870,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
Log.wtf(TAG, s);
}
private static void logwtf(String s, Throwable t) {
Log.wtf(TAG, s, t);
}
private static void loge(String s) {
Log.e(TAG, s);
}
@@ -8880,13 +8919,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
private int transportTypeToLegacyType(int type) {
switch (type) {
case NetworkCapabilities.TRANSPORT_CELLULAR:
return ConnectivityManager.TYPE_MOBILE;
return TYPE_MOBILE;
case NetworkCapabilities.TRANSPORT_WIFI:
return ConnectivityManager.TYPE_WIFI;
return TYPE_WIFI;
case NetworkCapabilities.TRANSPORT_BLUETOOTH:
return ConnectivityManager.TYPE_BLUETOOTH;
return TYPE_BLUETOOTH;
case NetworkCapabilities.TRANSPORT_ETHERNET:
return ConnectivityManager.TYPE_ETHERNET;
return TYPE_ETHERNET;
default:
loge("Unexpected transport in transportTypeToLegacyType: " + type);
}

View File

@@ -23,6 +23,8 @@ import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.FEATURE_WIFI;
import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
@@ -40,6 +42,7 @@ import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
@@ -1461,6 +1464,9 @@ public class ConnectivityServiceTest {
Looper.prepare();
}
mockDefaultPackages();
mockHasSystemFeature(FEATURE_WIFI, true);
mockHasSystemFeature(FEATURE_WIFI_DIRECT, true);
doReturn(true).when(mTelephonyManager).isDataCapable();
FakeSettingsProvider.clearSettingsProvider();
mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
@@ -1784,7 +1790,8 @@ public class ConnectivityServiceTest {
assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
assertFalse(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
assertFalse(mCm.isNetworkSupported(TYPE_PROXY));
// Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
// mocks, this assert exercises the ConnectivityService code path that ensures that

View File

@@ -21,13 +21,29 @@
package com.android.server
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FEATURE_WIFI
import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
import android.net.ConnectivityManager.TYPE_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_MOBILE_CBS
import android.net.ConnectivityManager.TYPE_MOBILE_DUN
import android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY
import android.net.ConnectivityManager.TYPE_MOBILE_FOTA
import android.net.ConnectivityManager.TYPE_MOBILE_HIPRI
import android.net.ConnectivityManager.TYPE_MOBILE_IA
import android.net.ConnectivityManager.TYPE_MOBILE_IMS
import android.net.ConnectivityManager.TYPE_MOBILE_MMS
import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
import android.net.ConnectivityManager.TYPE_VPN
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.ConnectivityManager.TYPE_WIFI_P2P
import android.net.ConnectivityManager.TYPE_WIMAX
import android.net.EthernetManager
import android.net.NetworkInfo.DetailedState.CONNECTED
import android.net.NetworkInfo.DetailedState.DISCONNECTED
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.server.ConnectivityService.LegacyTypeTracker
@@ -36,7 +52,6 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
@@ -52,88 +67,130 @@ const val UNSUPPORTED_TYPE = TYPE_WIMAX
@RunWith(AndroidJUnit4::class)
@SmallTest
class LegacyTypeTrackerTest {
private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
private val supportedTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_MOBILE,
TYPE_MOBILE_SUPL, TYPE_MOBILE_MMS, TYPE_MOBILE_SUPL, TYPE_MOBILE_DUN, TYPE_MOBILE_HIPRI,
TYPE_MOBILE_FOTA, TYPE_MOBILE_IMS, TYPE_MOBILE_CBS, TYPE_MOBILE_IA,
TYPE_MOBILE_EMERGENCY, TYPE_VPN)
private val mMockService = mock(ConnectivityService::class.java).apply {
doReturn(false).`when`(this).isDefaultNetwork(any())
}
private val mTracker = LegacyTypeTracker(mMockService).apply {
supportedTypes.forEach {
addSupportedType(it)
}
private val mPm = mock(PackageManager::class.java)
private val mContext = mock(Context::class.java).apply {
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI)
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
doReturn(mPm).`when`(this).packageManager
doReturn(mock(EthernetManager::class.java)).`when`(this).getSystemService(
Context.ETHERNET_SERVICE)
}
private val mTm = mock(TelephonyManager::class.java).apply {
doReturn(true).`when`(this).isDataCapable
}
private fun makeTracker() = LegacyTypeTracker(mMockService).apply {
loadSupportedTypes(mContext, mTm)
}
@Test
fun testSupportedTypes() {
try {
mTracker.addSupportedType(supportedTypes[0])
fail("Expected IllegalStateException")
} catch (expected: IllegalStateException) {}
val tracker = makeTracker()
supportedTypes.forEach {
assertTrue(mTracker.isTypeSupported(it))
assertTrue(tracker.isTypeSupported(it))
}
assertFalse(tracker.isTypeSupported(UNSUPPORTED_TYPE))
}
@Test
fun testSupportedTypes_NoEthernet() {
doReturn(null).`when`(mContext).getSystemService(Context.ETHERNET_SERVICE)
assertFalse(makeTracker().isTypeSupported(TYPE_ETHERNET))
}
@Test
fun testSupportedTypes_NoTelephony() {
doReturn(false).`when`(mTm).isDataCapable
val tracker = makeTracker()
val nonMobileTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_VPN)
nonMobileTypes.forEach {
assertTrue(tracker.isTypeSupported(it))
}
supportedTypes.toSet().minus(nonMobileTypes).forEach {
assertFalse(tracker.isTypeSupported(it))
}
}
@Test
fun testSupportedTypes_NoWifiDirect() {
doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
val tracker = makeTracker()
assertFalse(tracker.isTypeSupported(TYPE_WIFI_P2P))
supportedTypes.toSet().minus(TYPE_WIFI_P2P).forEach {
assertTrue(tracker.isTypeSupported(it))
}
assertFalse(mTracker.isTypeSupported(UNSUPPORTED_TYPE))
}
@Test
fun testSupl() {
val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
mTracker.add(TYPE_MOBILE, mobileNai)
tracker.add(TYPE_MOBILE, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
reset(mMockService)
mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
mTracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
tracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
mTracker.remove(mobileNai, false)
tracker.remove(mobileNai, false)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
}
@Test
fun testAddNetwork() {
val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
val wifiNai = mock(NetworkAgentInfo::class.java)
mTracker.add(TYPE_MOBILE, mobileNai)
mTracker.add(TYPE_WIFI, wifiNai)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
tracker.add(TYPE_MOBILE, mobileNai)
tracker.add(TYPE_WIFI, wifiNai)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a second NAI does not change the results.
val secondMobileNai = mock(NetworkAgentInfo::class.java)
mTracker.add(TYPE_MOBILE, secondMobileNai)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
tracker.add(TYPE_MOBILE, secondMobileNai)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure removing a network that wasn't added for this type is a no-op.
mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
tracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Remove the top network for mobile and make sure the second one becomes the network
// of record for this type.
mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
tracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
assertSame(tracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a network for an unsupported type does not register it.
mTracker.add(UNSUPPORTED_TYPE, mobileNai)
assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE))
tracker.add(UNSUPPORTED_TYPE, mobileNai)
assertNull(tracker.getNetworkForType(UNSUPPORTED_TYPE))
}
@Test
fun testBroadcastOnDisconnect() {
val tracker = makeTracker()
val mobileNai1 = mock(NetworkAgentInfo::class.java)
val mobileNai2 = mock(NetworkAgentInfo::class.java)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
mTracker.add(TYPE_MOBILE, mobileNai1)
tracker.add(TYPE_MOBILE, mobileNai1)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
reset(mMockService)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
mTracker.add(TYPE_MOBILE, mobileNai2)
tracker.add(TYPE_MOBILE, mobileNai2)
verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
tracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
}