[ST01] Attributes data usage of test network by specifier

Currently, data usage of all test networks are all attributed to
the same NetworkIdentity, which does not allow services to
distinguish upload & download traffic of different test networks.

Thus, this CL put specifier that comes along with
TestNetworkAgent into wifiNetworkKey field to build different
NetworkIdentity to attribute data usage to different for
individual networks. And allow querying test network usage with
wifiNetworkKeys.

Bug: 139774492
Test: atest FrameworksNetTests
      atest android.net.cts.ConnectivityManagerTest
Change-Id: I1bb38fd20781eaf3105735440a04b27bef36fcae
This commit is contained in:
Junyu Lai
2022-07-25 16:31:59 +08:00
parent d407328dd4
commit c9f1ca62d9
5 changed files with 149 additions and 21 deletions

View File

@@ -85,6 +85,12 @@ public class NetworkIdentity {
private static final long SUPPORTED_OEM_MANAGED_TYPES = OEM_PAID | OEM_PRIVATE; private static final long SUPPORTED_OEM_MANAGED_TYPES = OEM_PAID | OEM_PRIVATE;
// Need to be synchronized with ConnectivityManager.
// TODO: Use {@code ConnectivityManager#*} when visible.
static final int TYPE_TEST = 18;
private static final int MAX_NETWORK_TYPE = TYPE_TEST;
private static final int MIN_NETWORK_TYPE = TYPE_MOBILE;
final int mType; final int mType;
final int mRatType; final int mRatType;
final int mSubId; final int mSubId;
@@ -346,11 +352,6 @@ public class NetworkIdentity {
* Builder class for {@link NetworkIdentity}. * Builder class for {@link NetworkIdentity}.
*/ */
public static final class Builder { public static final class Builder {
// Need to be synchronized with ConnectivityManager.
// TODO: Use {@link ConnectivityManager#MAX_NETWORK_TYPE} when this file is in the module.
private static final int MAX_NETWORK_TYPE = 18; // TYPE_TEST
private static final int MIN_NETWORK_TYPE = TYPE_MOBILE;
private int mType; private int mType;
private int mRatType; private int mRatType;
private String mSubscriberId; private String mSubscriberId;
@@ -413,6 +414,12 @@ public class NetworkIdentity {
final WifiInfo info = (WifiInfo) transportInfo; final WifiInfo info = (WifiInfo) transportInfo;
setWifiNetworkKey(info.getNetworkKey()); setWifiNetworkKey(info.getNetworkKey());
} }
} else if (mType == TYPE_TEST) {
final NetworkSpecifier ns = snapshot.getNetworkCapabilities().getNetworkSpecifier();
if (ns instanceof TestNetworkSpecifier) {
// Reuse the wifi network key field to identify individual test networks.
setWifiNetworkKey(((TestNetworkSpecifier) ns).getInterfaceName());
}
} }
return this; return this;
} }
@@ -574,7 +581,7 @@ public class NetworkIdentity {
} }
// Assert non-wifi network cannot have a wifi network key. // Assert non-wifi network cannot have a wifi network key.
if (mType != TYPE_WIFI && mWifiNetworkKey != null) { if (mType != TYPE_WIFI && mType != TYPE_TEST && mWifiNetworkKey != null) {
throw new IllegalArgumentException("Invalid wifi network key for type " + mType); throw new IllegalArgumentException("Invalid wifi network key for type " + mType);
} }
} }

View File

@@ -50,6 +50,7 @@ import android.os.Parcelable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArraySet; import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkIdentityUtils; import com.android.net.module.util.NetworkIdentityUtils;
import com.android.net.module.util.NetworkStatsUtils; import com.android.net.module.util.NetworkStatsUtils;
@@ -114,6 +115,14 @@ public final class NetworkTemplate implements Parcelable {
* may offer non-cellular networks like WiFi, which will be matched by this rule. * may offer non-cellular networks like WiFi, which will be matched by this rule.
*/ */
public static final int MATCH_CARRIER = 10; public static final int MATCH_CARRIER = 10;
/**
* Match rule to match networks with {@link ConnectivityManager#TYPE_TEST} as the legacy
* network type.
*
* @hide
*/
@VisibleForTesting
public static final int MATCH_TEST = 11;
// TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL. // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL.
/** @hide */ /** @hide */
@@ -176,6 +185,7 @@ public final class NetworkTemplate implements Parcelable {
case MATCH_BLUETOOTH: case MATCH_BLUETOOTH:
case MATCH_PROXY: case MATCH_PROXY:
case MATCH_CARRIER: case MATCH_CARRIER:
case MATCH_TEST:
return true; return true;
default: default:
@@ -666,6 +676,8 @@ public final class NetworkTemplate implements Parcelable {
return matchesProxy(ident); return matchesProxy(ident);
case MATCH_CARRIER: case MATCH_CARRIER:
return matchesCarrier(ident); return matchesCarrier(ident);
case MATCH_TEST:
return matchesTest(ident);
default: default:
// We have no idea what kind of network template we are, so we // We have no idea what kind of network template we are, so we
// just claim not to match anything. // just claim not to match anything.
@@ -776,6 +788,17 @@ public final class NetworkTemplate implements Parcelable {
&& CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
} }
/**
* Check if matches test network. If the wifiNetworkKeys in the template is specified, Then it
* will only match a network containing any of the specified the wifi network key. Otherwise,
* all test networks would be matched.
*/
private boolean matchesTest(NetworkIdentity ident) {
return ident.mType == NetworkIdentity.TYPE_TEST
&& ((CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
|| CollectionUtils.contains(mMatchWifiNetworkKeys, ident.mWifiNetworkKey)));
}
private boolean matchesMobileWildcard(NetworkIdentity ident) { private boolean matchesMobileWildcard(NetworkIdentity ident) {
if (ident.mType == TYPE_WIMAX) { if (ident.mType == TYPE_WIMAX) {
return true; return true;
@@ -829,6 +852,8 @@ public final class NetworkTemplate implements Parcelable {
return "PROXY"; return "PROXY";
case MATCH_CARRIER: case MATCH_CARRIER:
return "CARRIER"; return "CARRIER";
case MATCH_TEST:
return "TEST";
default: default:
return "UNKNOWN(" + matchRule + ")"; return "UNKNOWN(" + matchRule + ")";
} }
@@ -1079,7 +1104,9 @@ public final class NetworkTemplate implements Parcelable {
} }
private void validateWifiNetworkKeys() { private void validateWifiNetworkKeys() {
if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) { // Also allow querying test networks which use wifi network key as identifier.
if (mMatchRule != MATCH_WIFI && mMatchRule != MATCH_TEST
&& !mMatchWifiNetworkKeys.isEmpty()) {
throw new IllegalArgumentException("Trying to build non wifi match rule: " throw new IllegalArgumentException("Trying to build non wifi match rule: "
+ mMatchRule + " with wifi network keys"); + mMatchRule + " with wifi network keys");
} }

View File

@@ -1167,6 +1167,8 @@ public class ConnectivityManager {
return "PROXY"; return "PROXY";
case TYPE_VPN: case TYPE_VPN:
return "VPN"; return "VPN";
case TYPE_TEST:
return "TEST";
default: default:
return Integer.toString(type); return Integer.toString(type);
} }

View File

@@ -19,7 +19,10 @@ package android.net
import android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA import android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA
import android.content.Context import android.content.Context
import android.net.ConnectivityManager.TYPE_MOBILE import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_TEST
import android.net.ConnectivityManager.TYPE_WIFI import android.net.ConnectivityManager.TYPE_WIFI
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkIdentity.OEM_NONE import android.net.NetworkIdentity.OEM_NONE
import android.net.NetworkIdentity.OEM_PAID import android.net.NetworkIdentity.OEM_PAID
import android.net.NetworkIdentity.OEM_PRIVATE import android.net.NetworkIdentity.OEM_PRIVATE
@@ -31,6 +34,7 @@ import android.net.NetworkStats.METERED_YES
import android.net.NetworkStats.ROAMING_ALL import android.net.NetworkStats.ROAMING_ALL
import android.net.NetworkTemplate.MATCH_MOBILE import android.net.NetworkTemplate.MATCH_MOBILE
import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
import android.net.NetworkTemplate.MATCH_TEST
import android.net.NetworkTemplate.MATCH_WIFI import android.net.NetworkTemplate.MATCH_WIFI
import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
import android.net.NetworkTemplate.NETWORK_TYPE_ALL import android.net.NetworkTemplate.NETWORK_TYPE_ALL
@@ -97,6 +101,14 @@ class NetworkTemplateTest {
(oemManaged and OEM_PAID) == OEM_PAID) (oemManaged and OEM_PAID) == OEM_PAID)
setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
(oemManaged and OEM_PRIVATE) == OEM_PRIVATE) (oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
if (type == TYPE_TEST) {
wifiKey?.let { TestNetworkSpecifier(it) }?.let {
// Must have a single non-test transport specified to use setNetworkSpecifier.
// Put an arbitrary transport type which is not used in this test.
addTransportType(TRANSPORT_TEST)
addTransportType(TRANSPORT_WIFI)
setNetworkSpecifier(it) }
}
setTransportInfo(mockWifiInfo) setTransportInfo(mockWifiInfo)
} }
return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type) return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
@@ -232,6 +244,32 @@ class NetworkTemplateTest {
templateMobileNullImsiWithRatType.assertDoesNotMatch(identWifiImsi1Key1) templateMobileNullImsiWithRatType.assertDoesNotMatch(identWifiImsi1Key1)
} }
@Test
fun testTestNetworkTemplateMatches() {
val templateTestKey1 = NetworkTemplate.Builder(MATCH_TEST)
.setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build()
val templateTestKey2 = NetworkTemplate.Builder(MATCH_TEST)
.setWifiNetworkKeys(setOf(TEST_WIFI_KEY2)).build()
val templateTestAll = NetworkTemplate.Builder(MATCH_TEST).build()
val stateWifiKey1 = buildNetworkState(TYPE_WIFI, null /* subscriberId */, TEST_WIFI_KEY1,
OEM_NONE, true /* metered */)
val stateTestKey1 = buildNetworkState(TYPE_TEST, null /* subscriberId */, TEST_WIFI_KEY1,
OEM_NONE, true /* metered */)
val identWifi1 = buildNetworkIdentity(mockContext, stateWifiKey1,
false /* defaultNetwork */, NetworkTemplate.NETWORK_TYPE_ALL)
val identTest1 = buildNetworkIdentity(mockContext, stateTestKey1,
false /* defaultNetwork */, NETWORK_TYPE_ALL)
// Verify that the template matches corresponding type and the subscriberId.
templateTestKey1.assertDoesNotMatch(identWifi1)
templateTestKey1.assertMatches(identTest1)
templateTestKey2.assertDoesNotMatch(identWifi1)
templateTestKey2.assertDoesNotMatch(identTest1)
templateTestAll.assertDoesNotMatch(identWifi1)
templateTestAll.assertMatches(identTest1)
}
@Test @Test
fun testCarrierMeteredMatches() { fun testCarrierMeteredMatches() {
val templateCarrierImsi1Metered = buildTemplateCarrierMetered(TEST_IMSI1) val templateCarrierImsi1Metered = buildTemplateCarrierMetered(TEST_IMSI1)

View File

@@ -25,6 +25,7 @@ import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_TEST;
import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkIdentity.OEM_PAID; import static android.net.NetworkIdentity.OEM_PAID;
import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkIdentity.OEM_PRIVATE;
@@ -48,6 +49,7 @@ import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.MATCH_MOBILE; import static android.net.NetworkTemplate.MATCH_MOBILE;
import static android.net.NetworkTemplate.MATCH_TEST;
import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.OEM_MANAGED_NO; import static android.net.NetworkTemplate.OEM_MANAGED_NO;
import static android.net.NetworkTemplate.OEM_MANAGED_YES; import static android.net.NetworkTemplate.OEM_MANAGED_YES;
@@ -107,6 +109,7 @@ import android.net.NetworkStatsCollection;
import android.net.NetworkStatsHistory; import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate; import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier; import android.net.TelephonyNetworkSpecifier;
import android.net.TestNetworkSpecifier;
import android.net.TetherStatsParcel; import android.net.TetherStatsParcel;
import android.net.TetheringManager; import android.net.TetheringManager;
import android.net.UnderlyingNetworkInfo; import android.net.UnderlyingNetworkInfo;
@@ -121,6 +124,7 @@ import android.os.SimpleClock;
import android.provider.Settings; import android.provider.Settings;
import android.system.ErrnoException; import android.system.ErrnoException;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Pair; import android.util.Pair;
@@ -209,9 +213,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
private static final Network WIFI_NETWORK = new Network(100); private static final Network WIFI_NETWORK = new Network(100);
private static final Network MOBILE_NETWORK = new Network(101); private static final Network MOBILE_NETWORK = new Network(101);
private static final Network VPN_NETWORK = new Network(102); private static final Network VPN_NETWORK = new Network(102);
private static final Network TEST_NETWORK = new Network(103);
private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK }; private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK }; private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
private static final Network[] NETWORKS_TEST = new Network[]{ TEST_NETWORK };
private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
private static final int INVALID_TYPE = -1; private static final int INVALID_TYPE = -1;
@@ -817,7 +823,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0); assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0);
assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0); assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
// now pretend two UIDs are uninstalled, which should migrate stats to // now pretend two UIDs are uninstalled, which should migrate stats to
// special "removed" bucket. // special "removed" bucket.
mockDefaultSettings(); mockDefaultSettings();
@@ -940,8 +945,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// Pretend that 5g mobile network comes online // Pretend that 5g mobile network comes online
final NetworkStateSnapshot[] mobileStates = final NetworkStateSnapshot[] mobileStates =
new NetworkStateSnapshot[] {buildMobileState(IMSI_1), buildMobileState(TEST_IFACE2, new NetworkStateSnapshot[] {buildMobileState(IMSI_1), buildStateOfTransport(
IMSI_1, true /* isTemporarilyNotMetered */, false /* isRoaming */)}; NetworkCapabilities.TRANSPORT_CELLULAR, TYPE_MOBILE,
TEST_IFACE2, IMSI_1, null /* wifiNetworkKey */,
true /* isTemporarilyNotMetered */, false /* isRoaming */)};
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR); setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR);
mService.notifyNetworkStatus(NETWORKS_MOBILE, mobileStates, mService.notifyNetworkStatus(NETWORKS_MOBILE, mobileStates,
getActiveIface(mobileStates), new UnderlyingNetworkInfo[0]); getActiveIface(mobileStates), new UnderlyingNetworkInfo[0]);
@@ -1172,6 +1179,41 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// already documented publicly, refer to {@link NetworkStatsManager#queryDetails}. // already documented publicly, refer to {@link NetworkStatsManager#queryDetails}.
} }
@Test
public void testQueryTestNetworkUsage() throws Exception {
final NetworkTemplate templateTestAll = new NetworkTemplate.Builder(MATCH_TEST).build();
final NetworkTemplate templateTestIface1 = new NetworkTemplate.Builder(MATCH_TEST)
.setWifiNetworkKeys(Set.of(TEST_IFACE)).build();
final NetworkTemplate templateTestIface2 = new NetworkTemplate.Builder(MATCH_TEST)
.setWifiNetworkKeys(Set.of(TEST_IFACE2)).build();
// Test networks might use interface as subscriberId to identify individual networks.
// Simulate both cases.
final NetworkStateSnapshot[] states =
new NetworkStateSnapshot[]{buildTestState(TEST_IFACE, TEST_IFACE),
buildTestState(TEST_IFACE2, null /* wifiNetworkKey */)};
// Test networks comes online.
mockNetworkStatsSummary(buildEmptyStats());
mockNetworkStatsUidDetail(buildEmptyStats());
mService.notifyNetworkStatus(NETWORKS_TEST, states, getActiveIface(states),
new UnderlyingNetworkInfo[0]);
// Create some traffic on both interfaces.
incrementCurrentTime(MINUTE_IN_MILLIS);
mockNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12L, 18L, 14L, 1L, 0L))
.addEntry(new NetworkStats.Entry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7L, 3L, 5L, 1L, 1L)));
forcePollAndWaitForIdle();
// Verify test network templates gets stats. Stats of test networks without subscriberId
// can only be matched by templates without subscriberId requirement.
assertUidTotal(templateTestAll, UID_RED, 19L, 21L, 19L, 2L, 1);
assertUidTotal(templateTestIface1, UID_RED, 12L, 18L, 14L, 1L, 0);
assertUidTotal(templateTestIface2, UID_RED, 0L, 0L, 0L, 0L, 0);
}
@Test @Test
public void testUidStatsForTransport() throws Exception { public void testUidStatsForTransport() throws Exception {
// pretend that network comes online // pretend that network comes online
@@ -1319,8 +1361,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// pretend that network comes online // pretend that network comes online
mockDefaultSettings(); mockDefaultSettings();
NetworkStateSnapshot[] states = NetworkStateSnapshot[] states =
new NetworkStateSnapshot[] {buildMobileState(TEST_IFACE, IMSI_1, new NetworkStateSnapshot[] {buildStateOfTransport(
false /* isTemporarilyNotMetered */, true /* isRoaming */)}; NetworkCapabilities.TRANSPORT_CELLULAR, TYPE_MOBILE,
TEST_IFACE, IMSI_1, null /* wifiNetworkKey */,
false /* isTemporarilyNotMetered */, true /* isRoaming */)};
mockNetworkStatsSummary(buildEmptyStats()); mockNetworkStatsSummary(buildEmptyStats());
mockNetworkStatsUidDetail(buildEmptyStats()); mockNetworkStatsUidDetail(buildEmptyStats());
@@ -2189,24 +2233,34 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
} }
private static NetworkStateSnapshot buildMobileState(String subscriberId) { private static NetworkStateSnapshot buildMobileState(String subscriberId) {
return buildMobileState(TEST_IFACE, subscriberId, false /* isTemporarilyNotMetered */, return buildStateOfTransport(NetworkCapabilities.TRANSPORT_CELLULAR, TYPE_MOBILE,
false /* isRoaming */); TEST_IFACE, subscriberId, null /* wifiNetworkKey */,
false /* isTemporarilyNotMetered */, false /* isRoaming */);
} }
private static NetworkStateSnapshot buildMobileState(String iface, String subscriberId, private static NetworkStateSnapshot buildTestState(@NonNull String iface,
@Nullable String wifiNetworkKey) {
return buildStateOfTransport(NetworkCapabilities.TRANSPORT_TEST, TYPE_TEST,
iface, null /* subscriberId */, wifiNetworkKey,
false /* isTemporarilyNotMetered */, false /* isRoaming */);
}
private static NetworkStateSnapshot buildStateOfTransport(int transport, int legacyType,
String iface, String subscriberId, String wifiNetworkKey,
boolean isTemporarilyNotMetered, boolean isRoaming) { boolean isTemporarilyNotMetered, boolean isRoaming) {
final LinkProperties prop = new LinkProperties(); final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(iface); prop.setInterfaceName(iface);
final NetworkCapabilities capabilities = new NetworkCapabilities(); final NetworkCapabilities capabilities = new NetworkCapabilities();
if (isTemporarilyNotMetered) { capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED,
capabilities.addCapability( isTemporarilyNotMetered);
NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
}
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming); capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); capabilities.addTransportType(transport);
if (legacyType == TYPE_TEST && !TextUtils.isEmpty(wifiNetworkKey)) {
capabilities.setNetworkSpecifier(new TestNetworkSpecifier(wifiNetworkKey));
}
return new NetworkStateSnapshot( return new NetworkStateSnapshot(
MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE); MOBILE_NETWORK, capabilities, prop, subscriberId, legacyType);
} }
private NetworkStats buildEmptyStats() { private NetworkStats buildEmptyStats() {