Merge "Remove usage of networkAttributes"

This commit is contained in:
Remi NGUYEN VAN
2021-03-17 11:24:28 +00:00
committed by Gerrit Code Review
5 changed files with 218 additions and 105 deletions

View File

@@ -42,4 +42,14 @@
--> -->
</string-array> </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> </resources>

View File

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

View File

@@ -17,6 +17,10 @@
package com.android.server; package com.android.server;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; 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.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_ATTEMPTED_BITMASK;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_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.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; 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_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_NONE;
import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN; 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.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
@@ -112,7 +130,6 @@ import android.net.Network;
import android.net.NetworkAgent; import android.net.NetworkAgent;
import android.net.NetworkAgentConfig; import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMonitorManager; import android.net.NetworkMonitorManager;
@@ -626,11 +643,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private UserManager mUserManager; private UserManager mUserManager;
private NetworkConfig[] mNetConfigs;
private int mNetworksDefined;
// the set of network types that can only be enabled by system/sig apps // 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; private Set<String> mWolSupportedInterfaces;
@@ -720,18 +734,63 @@ public class ConnectivityService extends IConnectivityManager.Stub
* They are therefore not thread-safe with respect to each other. * They are therefore not thread-safe with respect to each other.
* - getNetworkForType() can be called at any time on binder threads. It is synchronized * - 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. * 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. * - dump is thread-safe with respect to concurrent add and remove calls.
*/ */
private final ArrayList<NetworkAgentInfo> mTypeLists[]; private final ArrayList<NetworkAgentInfo> mTypeLists[];
@NonNull @NonNull
private final ConnectivityService mService; 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) { LegacyTypeTracker(@NonNull ConnectivityService service) {
mService = service; mService = service;
mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; 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) { if (mTypeLists[type] != null) {
throw new IllegalStateException( throw new IllegalStateException(
"legacy list for type " + type + "already initialized"); "legacy list for type " + type + "already initialized");
@@ -752,6 +811,35 @@ public class ConnectivityService extends IConnectivityManager.Stub
return null; 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, private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
boolean isDefaultNetwork) { boolean isDefaultNetwork) {
if (DBG) { if (DBG) {
@@ -1174,64 +1262,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; mLegacyTypeTracker.loadSupportedTypes(mContext, mTelephonyManager);
mProtectedNetworks = new ArrayList<>();
// 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>();
int[] protectedNetworks = context.getResources().getIntArray( int[] protectedNetworks = context.getResources().getIntArray(
com.android.internal.R.array.config_protectedNetworks); com.android.internal.R.array.config_protectedNetworks);
for (int p : protectedNetworks) { for (int p : protectedNetworks) {
if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) { if (mLegacyTypeTracker.isTypeSupported(p) && !mProtectedNetworks.contains(p)) {
mProtectedNetworks.add(p); mProtectedNetworks.add(p);
} else { } else {
if (DBG) loge("Ignoring protectedNetwork " + p); if (DBG) loge("Ignoring protectedNetwork " + p);
@@ -2640,9 +2676,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if the system property isn't set, use the value for the apn type // if the system property isn't set, use the value for the apn type
int ret = RESTORE_DEFAULT_NETWORK_DELAY; int ret = RESTORE_DEFAULT_NETWORK_DELAY;
if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) && if (mLegacyTypeTracker.isTypeSupported(networkType)) {
(mNetConfigs[networkType] != null)) { ret = mLegacyTypeTracker.getRestoreTimerForType(networkType);
ret = mNetConfigs[networkType].restoreTime;
} }
return ret; return ret;
} }
@@ -4855,6 +4890,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
Log.wtf(TAG, s); Log.wtf(TAG, s);
} }
private static void logwtf(String s, Throwable t) {
Log.wtf(TAG, s, t);
}
private static void loge(String s) { private static void loge(String s) {
Log.e(TAG, s); Log.e(TAG, s);
} }
@@ -8917,13 +8956,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
private int transportTypeToLegacyType(int type) { private int transportTypeToLegacyType(int type) {
switch (type) { switch (type) {
case NetworkCapabilities.TRANSPORT_CELLULAR: case NetworkCapabilities.TRANSPORT_CELLULAR:
return ConnectivityManager.TYPE_MOBILE; return TYPE_MOBILE;
case NetworkCapabilities.TRANSPORT_WIFI: case NetworkCapabilities.TRANSPORT_WIFI:
return ConnectivityManager.TYPE_WIFI; return TYPE_WIFI;
case NetworkCapabilities.TRANSPORT_BLUETOOTH: case NetworkCapabilities.TRANSPORT_BLUETOOTH:
return ConnectivityManager.TYPE_BLUETOOTH; return TYPE_BLUETOOTH;
case NetworkCapabilities.TRANSPORT_ETHERNET: case NetworkCapabilities.TRANSPORT_ETHERNET:
return ConnectivityManager.TYPE_ETHERNET; return TYPE_ETHERNET;
default: default:
loge("Unexpected transport in transportTypeToLegacyType: " + type); 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_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED; import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; 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.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_DENIED;
@@ -42,6 +44,7 @@ import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; 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_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS; import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
@@ -1505,6 +1508,9 @@ public class ConnectivityServiceTest {
Looper.prepare(); Looper.prepare();
} }
mockDefaultPackages(); mockDefaultPackages();
mockHasSystemFeature(FEATURE_WIFI, true);
mockHasSystemFeature(FEATURE_WIFI_DIRECT, true);
doReturn(true).when(mTelephonyManager).isDataCapable();
FakeSettingsProvider.clearSettingsProvider(); FakeSettingsProvider.clearSettingsProvider();
mServiceContext = new MockContext(InstrumentationRegistry.getContext(), mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
@@ -1829,7 +1835,8 @@ public class ConnectivityServiceTest {
assertTrue(mCm.isNetworkSupported(TYPE_WIFI)); assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE)); assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS)); 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 // 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 // mocks, this assert exercises the ConnectivityService code path that ensures that

View File

@@ -21,13 +21,29 @@
package com.android.server 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_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE 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_MOBILE_SUPL
import android.net.ConnectivityManager.TYPE_VPN
import android.net.ConnectivityManager.TYPE_WIFI import android.net.ConnectivityManager.TYPE_WIFI
import android.net.ConnectivityManager.TYPE_WIFI_P2P
import android.net.ConnectivityManager.TYPE_WIMAX import android.net.ConnectivityManager.TYPE_WIMAX
import android.net.EthernetManager
import android.net.NetworkInfo.DetailedState.CONNECTED import android.net.NetworkInfo.DetailedState.CONNECTED
import android.net.NetworkInfo.DetailedState.DISCONNECTED import android.net.NetworkInfo.DetailedState.DISCONNECTED
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import com.android.server.ConnectivityService.LegacyTypeTracker import com.android.server.ConnectivityService.LegacyTypeTracker
@@ -36,7 +52,6 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull import org.junit.Assert.assertNull
import org.junit.Assert.assertSame import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Assert.fail
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.any
@@ -52,88 +67,130 @@ const val UNSUPPORTED_TYPE = TYPE_WIMAX
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@SmallTest @SmallTest
class LegacyTypeTrackerTest { 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 { private val mMockService = mock(ConnectivityService::class.java).apply {
doReturn(false).`when`(this).isDefaultNetwork(any()) doReturn(false).`when`(this).isDefaultNetwork(any())
} }
private val mTracker = LegacyTypeTracker(mMockService).apply { private val mPm = mock(PackageManager::class.java)
supportedTypes.forEach { private val mContext = mock(Context::class.java).apply {
addSupportedType(it) 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 @Test
fun testSupportedTypes() { fun testSupportedTypes() {
try { val tracker = makeTracker()
mTracker.addSupportedType(supportedTypes[0])
fail("Expected IllegalStateException")
} catch (expected: IllegalStateException) {}
supportedTypes.forEach { 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 @Test
fun testSupl() { fun testSupl() {
val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java) val mobileNai = mock(NetworkAgentInfo::class.java)
mTracker.add(TYPE_MOBILE, mobileNai) tracker.add(TYPE_MOBILE, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE) verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
reset(mMockService) reset(mMockService)
mTracker.add(TYPE_MOBILE_SUPL, mobileNai) tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL) verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService) 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) verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService) reset(mMockService)
mTracker.add(TYPE_MOBILE_SUPL, mobileNai) tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL) verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService) 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_SUPL)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE) verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
} }
@Test @Test
fun testAddNetwork() { fun testAddNetwork() {
val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java) val mobileNai = mock(NetworkAgentInfo::class.java)
val wifiNai = mock(NetworkAgentInfo::class.java) val wifiNai = mock(NetworkAgentInfo::class.java)
mTracker.add(TYPE_MOBILE, mobileNai) tracker.add(TYPE_MOBILE, mobileNai)
mTracker.add(TYPE_WIFI, wifiNai) tracker.add(TYPE_WIFI, wifiNai)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai) assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a second NAI does not change the results. // Make sure adding a second NAI does not change the results.
val secondMobileNai = mock(NetworkAgentInfo::class.java) val secondMobileNai = mock(NetworkAgentInfo::class.java)
mTracker.add(TYPE_MOBILE, secondMobileNai) tracker.add(TYPE_MOBILE, secondMobileNai)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai) assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure removing a network that wasn't added for this type is a no-op. // Make sure removing a network that wasn't added for this type is a no-op.
mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */) tracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai) assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Remove the top network for mobile and make sure the second one becomes the network // Remove the top network for mobile and make sure the second one becomes the network
// of record for this type. // of record for this type.
mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */) tracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai) assertSame(tracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a network for an unsupported type does not register it. // Make sure adding a network for an unsupported type does not register it.
mTracker.add(UNSUPPORTED_TYPE, mobileNai) tracker.add(UNSUPPORTED_TYPE, mobileNai)
assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE)) assertNull(tracker.getNetworkForType(UNSUPPORTED_TYPE))
} }
@Test @Test
fun testBroadcastOnDisconnect() { fun testBroadcastOnDisconnect() {
val tracker = makeTracker()
val mobileNai1 = mock(NetworkAgentInfo::class.java) val mobileNai1 = mock(NetworkAgentInfo::class.java)
val mobileNai2 = mock(NetworkAgentInfo::class.java) val mobileNai2 = mock(NetworkAgentInfo::class.java)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1) doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
mTracker.add(TYPE_MOBILE, mobileNai1) tracker.add(TYPE_MOBILE, mobileNai1)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE) verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
reset(mMockService) reset(mMockService)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2) doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
mTracker.add(TYPE_MOBILE, mobileNai2) tracker.add(TYPE_MOBILE, mobileNai2)
verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt()) 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(mobileNai1, DISCONNECTED, TYPE_MOBILE)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE) verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
} }