Merge "[ST01] Attributes data usage of test network by specifier"

This commit is contained in:
Junyu Lai
2022-08-30 05:50:40 +00:00
committed by Gerrit Code Review
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;
// 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 mRatType;
final int mSubId;
@@ -346,11 +352,6 @@ public class NetworkIdentity {
* Builder class for {@link NetworkIdentity}.
*/
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 mRatType;
private String mSubscriberId;
@@ -413,6 +414,12 @@ public class NetworkIdentity {
final WifiInfo info = (WifiInfo) transportInfo;
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;
}
@@ -574,7 +581,7 @@ public class NetworkIdentity {
}
// 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);
}
}

View File

@@ -50,6 +50,7 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkIdentityUtils;
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.
*/
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.
/** @hide */
@@ -176,6 +185,7 @@ public final class NetworkTemplate implements Parcelable {
case MATCH_BLUETOOTH:
case MATCH_PROXY:
case MATCH_CARRIER:
case MATCH_TEST:
return true;
default:
@@ -666,6 +676,8 @@ public final class NetworkTemplate implements Parcelable {
return matchesProxy(ident);
case MATCH_CARRIER:
return matchesCarrier(ident);
case MATCH_TEST:
return matchesTest(ident);
default:
// We have no idea what kind of network template we are, so we
// just claim not to match anything.
@@ -776,6 +788,17 @@ public final class NetworkTemplate implements Parcelable {
&& 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) {
if (ident.mType == TYPE_WIMAX) {
return true;
@@ -829,6 +852,8 @@ public final class NetworkTemplate implements Parcelable {
return "PROXY";
case MATCH_CARRIER:
return "CARRIER";
case MATCH_TEST:
return "TEST";
default:
return "UNKNOWN(" + matchRule + ")";
}
@@ -1079,7 +1104,9 @@ public final class NetworkTemplate implements Parcelable {
}
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: "
+ mMatchRule + " with wifi network keys");
}

View File

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

View File

@@ -19,7 +19,10 @@ package android.net
import android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA
import android.content.Context
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_TEST
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_PAID
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.NetworkTemplate.MATCH_MOBILE
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_WILDCARD
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
@@ -97,6 +101,14 @@ class NetworkTemplateTest {
(oemManaged and OEM_PAID) == OEM_PAID)
setCapability(NetworkCapabilities.NET_CAPABILITY_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)
}
return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
@@ -232,6 +244,32 @@ class NetworkTemplateTest {
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
fun testCarrierMeteredMatches() {
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_GRANTED;
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.NetworkIdentity.OEM_PAID;
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.NetworkStatsHistory.FIELD_ALL;
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.OEM_MANAGED_NO;
import static android.net.NetworkTemplate.OEM_MANAGED_YES;
@@ -107,6 +109,7 @@ import android.net.NetworkStatsCollection;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
import android.net.TestNetworkSpecifier;
import android.net.TetherStatsParcel;
import android.net.TetheringManager;
import android.net.UnderlyingNetworkInfo;
@@ -121,6 +124,7 @@ import android.os.SimpleClock;
import android.provider.Settings;
import android.system.ErrnoException;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
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 MOBILE_NETWORK = new Network(101);
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_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 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_GREEN, 16L, 1L, 16L, 1L, 0);
// now pretend two UIDs are uninstalled, which should migrate stats to
// special "removed" bucket.
mockDefaultSettings();
@@ -940,8 +945,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// Pretend that 5g mobile network comes online
final NetworkStateSnapshot[] mobileStates =
new NetworkStateSnapshot[] {buildMobileState(IMSI_1), buildMobileState(TEST_IFACE2,
IMSI_1, true /* isTemporarilyNotMetered */, false /* isRoaming */)};
new NetworkStateSnapshot[] {buildMobileState(IMSI_1), buildStateOfTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, TYPE_MOBILE,
TEST_IFACE2, IMSI_1, null /* wifiNetworkKey */,
true /* isTemporarilyNotMetered */, false /* isRoaming */)};
setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR);
mService.notifyNetworkStatus(NETWORKS_MOBILE, mobileStates,
getActiveIface(mobileStates), new UnderlyingNetworkInfo[0]);
@@ -1172,6 +1179,41 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// 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
public void testUidStatsForTransport() throws Exception {
// pretend that network comes online
@@ -1319,8 +1361,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
// pretend that network comes online
mockDefaultSettings();
NetworkStateSnapshot[] states =
new NetworkStateSnapshot[] {buildMobileState(TEST_IFACE, IMSI_1,
false /* isTemporarilyNotMetered */, true /* isRoaming */)};
new NetworkStateSnapshot[] {buildStateOfTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, TYPE_MOBILE,
TEST_IFACE, IMSI_1, null /* wifiNetworkKey */,
false /* isTemporarilyNotMetered */, true /* isRoaming */)};
mockNetworkStatsSummary(buildEmptyStats());
mockNetworkStatsUidDetail(buildEmptyStats());
@@ -2189,24 +2233,34 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
}
private static NetworkStateSnapshot buildMobileState(String subscriberId) {
return buildMobileState(TEST_IFACE, subscriberId, false /* isTemporarilyNotMetered */,
false /* isRoaming */);
return buildStateOfTransport(NetworkCapabilities.TRANSPORT_CELLULAR, TYPE_MOBILE,
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) {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(iface);
final NetworkCapabilities capabilities = new NetworkCapabilities();
if (isTemporarilyNotMetered) {
capabilities.addCapability(
NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
}
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED,
isTemporarilyNotMetered);
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(
MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
MOBILE_NETWORK, capabilities, prop, subscriberId, legacyType);
}
private NetworkStats buildEmptyStats() {