Merge changes I036b7f23,I53c58e7b
* changes:
Improve the JavaDoc for FIREWALL_CHAIN_OEM_DENY_x.
Allow tests to set the NetworkAgent's callbacks when creating it.
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index c76416f..c32742b 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -43,14 +43,9 @@
":framework-connectivity-tiramisu-updatable-sources",
":framework-nearby-java-sources",
],
- stub_only_libs: [
- // Use prebuilt framework-connectivity stubs to avoid circular dependencies
- "sdk_module-lib_current_framework-connectivity",
- ],
libs: [
"unsupportedappusage",
"app-compat-annotations",
- "sdk_module-lib_current_framework-connectivity",
],
impl_only_libs: [
// The build system will use framework-bluetooth module_current stubs, because
@@ -104,6 +99,13 @@
// The jarjar rules are only so that references to jarjared utils in
// framework-connectivity-pre-jarjar match at runtime.
jarjar_rules: ":framework-connectivity-jarjar-rules",
+ stub_only_libs: [
+ // Use prebuilt framework-connectivity stubs to avoid circular dependencies
+ "sdk_module-lib_current_framework-connectivity",
+ ],
+ libs: [
+ "sdk_module-lib_current_framework-connectivity",
+ ],
permitted_packages: [
"android.app.usage",
"android.net",
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index cab3852..1fbbd25 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1107,7 +1107,7 @@
/**
* Tests if a given integer represents a valid network type.
* @param networkType the type to be tested
- * @return a boolean. {@code true} if the type is valid, else {@code false}
+ * @return {@code true} if the type is valid, else {@code false}
* @deprecated All APIs accepting a network type are deprecated. There should be no need to
* validate a network type.
*/
@@ -1466,9 +1466,8 @@
}
/**
- * Returns details about the currently active default data network
- * for a given uid. This is for internal use only to avoid spying
- * other apps.
+ * Returns details about the currently active default data network for a given uid.
+ * This is for privileged use only to avoid spying on other apps.
*
* @return a {@link NetworkInfo} object for the current default network
* for the given uid or {@code null} if no default network is
@@ -1492,8 +1491,7 @@
}
/**
- * Returns connection status information about a particular
- * network type.
+ * Returns connection status information about a particular network type.
*
* @param networkType integer specifying which networkType in
* which you're interested.
@@ -1521,8 +1519,7 @@
}
/**
- * Returns connection status information about a particular
- * Network.
+ * Returns connection status information about a particular Network.
*
* @param network {@link Network} specifying which network
* in which you're interested.
@@ -1548,8 +1545,7 @@
}
/**
- * Returns connection status information about all network
- * types supported by the device.
+ * Returns connection status information about all network types supported by the device.
*
* @return an array of {@link NetworkInfo} objects. Check each
* {@link NetworkInfo#getType} for which type each applies.
@@ -1609,8 +1605,7 @@
}
/**
- * Returns an array of all {@link Network} currently tracked by the
- * framework.
+ * Returns an array of all {@link Network} currently tracked by the framework.
*
* @deprecated This method does not provide any notification of network state changes, forcing
* apps to call it repeatedly. This is inefficient and prone to race conditions.
@@ -1813,7 +1808,7 @@
* that may be relevant for other components trying to detect captive portals.
*
* @hide
- * @deprecated This API returns URL which is not guaranteed to be one of the URLs used by the
+ * @deprecated This API returns a URL which is not guaranteed to be one of the URLs used by the
* system.
*/
@Deprecated
@@ -2392,8 +2387,7 @@
}
/**
- * Request that keepalives be started on a TCP socket.
- * The socket must be established.
+ * Request that keepalives be started on a TCP socket. The socket must be established.
*
* @param network The {@link Network} the socket is on.
* @param socket The socket that needs to be kept alive.
@@ -2680,7 +2674,7 @@
}
/**
- * Check if the package is a allowed to write settings. This also accounts that such an access
+ * Check if the package is allowed to write settings. This also records that such an access
* happened.
*
* @return {@code true} iff the package is allowed to write settings.
@@ -2783,7 +2777,7 @@
}
/**
- * Attempt to tether the named interface. This will setup a dhcp server
+ * Attempt to tether the named interface. This will set up a dhcp server
* on the interface, forward and NAT IP packets and forward DNS requests
* to the best active upstream network interface. Note that if no upstream
* IP network interface is available, dhcp will still run and traffic will be
@@ -3292,10 +3286,10 @@
/**
* Get the last value of the entitlement check on this downstream. If the cached value is
- * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
- * cached value. Otherwise, a UI-based entitlement check would be performed. It is not
+ * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, this just returns the
+ * cached value. Otherwise, a UI-based entitlement check will be performed. It is not
* guaranteed that the UI-based entitlement check will complete in any specific time period
- * and may in fact never complete. Any successful entitlement check the platform performs for
+ * and it may in fact never complete. Any successful entitlement check the platform performs for
* any reason will update the cached value.
*
* @param type the downstream type of tethering. Must be one of
@@ -3482,12 +3476,11 @@
}
/**
- * Returns true if the hardware supports the given network type
- * else it returns false. This doesn't indicate we have coverage
- * or are authorized onto a network, just whether or not the
- * hardware supports it. For example a GSM phone without a SIM
- * should still return {@code true} for mobile data, but a wifi only
- * tablet would return {@code false}.
+ * Returns whether the hardware supports the given network type.
+ *
+ * This doesn't indicate there is coverage or such a network is available, just whether the
+ * hardware supports it. For example a GSM phone without a SIM card will return {@code true}
+ * for mobile data, but a WiFi only tablet would return {@code false}.
*
* @param networkType The network type we'd like to check
* @return {@code true} if supported, else {@code false}
@@ -4853,9 +4846,8 @@
* Unregisters a {@code NetworkCallback} and possibly releases networks originating from
* {@link #requestNetwork(NetworkRequest, NetworkCallback)} and
* {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} calls.
- * If the given {@code NetworkCallback} had previously been used with
- * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request
- * will be disconnected.
+ * If the given {@code NetworkCallback} had previously been used with {@code #requestNetwork},
+ * any networks that the device brought up only to satisfy that request will be disconnected.
*
* Notifications that would have triggered that {@code NetworkCallback} will immediately stop
* triggering it as soon as this call returns.
@@ -4990,7 +4982,7 @@
}
/**
- * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration.
+ * Temporarily allow bad Wi-Fi to override {@code config_networkAvoidBadWifi} configuration.
*
* @param timeMs The expired current time. The value should be set within a limited time from
* now.
@@ -5049,7 +5041,7 @@
}
/**
- * Determine whether the device is configured to avoid bad wifi.
+ * Determine whether the device is configured to avoid bad Wi-Fi.
* @hide
*/
@SystemApi
@@ -5118,9 +5110,9 @@
* each such operation.
*
* @param network The network on which the application desires to use multipath data.
- * If {@code null}, this method will return the a preference that will generally
+ * If {@code null}, this method will return a preference that will generally
* apply to metered networks.
- * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
+ * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public @MultipathPreference int getMultipathPreference(@Nullable Network network) {
@@ -5233,7 +5225,7 @@
*/
@Nullable
public Network getBoundNetworkForProcess() {
- // Forcing callers to call thru non-static function ensures ConnectivityManager
+ // Forcing callers to call through non-static function ensures ConnectivityManager has been
// instantiated.
return getProcessDefaultNetwork();
}
@@ -5878,7 +5870,7 @@
}
/**
- * Removes the specified UID from the list of UIds that can use use background data on metered
+ * Removes the specified UID from the list of UIDs that can use background data on metered
* networks if background data is not restricted. The deny list takes precedence over the
* allow list.
*
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 77931b1..a95aa85 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -53,6 +53,7 @@
import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT;
import static android.os.Trace.TRACE_TAG_NETWORK;
import static android.system.OsConstants.ENOENT;
+import static android.system.OsConstants.R_OK;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
@@ -130,6 +131,7 @@
import android.service.NetworkInterfaceProto;
import android.service.NetworkStatsServiceDumpProto;
import android.system.ErrnoException;
+import android.system.Os;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionPlan;
import android.text.TextUtils;
@@ -156,6 +158,7 @@
import com.android.net.module.util.LocationPermissionChecker;
import com.android.net.module.util.NetworkStatsUtils;
import com.android.net.module.util.PermissionUtils;
+import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.U32;
import com.android.net.module.util.Struct.U8;
import com.android.net.module.util.bpf.CookieTagMapKey;
@@ -2698,6 +2701,23 @@
mUidTagRecorder.dumpLocked(pw, fullHistory);
pw.decreaseIndent();
}
+
+ pw.println();
+ pw.println("BPF map status:");
+ pw.increaseIndent();
+ dumpMapStatus(pw);
+ pw.decreaseIndent();
+ pw.println();
+
+ // Following BPF map content dump contains uid and tag regardless of the flags because
+ // following dumps are moved from TrafficController and bug report already contains this
+ // information.
+ pw.println("BPF map content:");
+ pw.increaseIndent();
+ dumpCookieTagMapLocked(pw);
+ dumpUidCounterSetMapLocked(pw);
+ dumpAppUidStatsMapLocked(pw);
+ pw.decreaseIndent();
}
}
@@ -2732,6 +2752,102 @@
}
}
+ private <K extends Struct, V extends Struct> String getMapStatus(
+ final IBpfMap<K, V> map, final String path) {
+ if (map != null) {
+ return "OK";
+ }
+ try {
+ Os.access(path, R_OK);
+ return "NULL(map is pinned to " + path + ")";
+ } catch (ErrnoException e) {
+ return "NULL(map is not pinned to " + path + ": " + Os.strerror(e.errno) + ")";
+ }
+ }
+
+ private void dumpMapStatus(final IndentingPrintWriter pw) {
+ pw.println("mCookieTagMap: " + getMapStatus(mCookieTagMap, COOKIE_TAG_MAP_PATH));
+ pw.println("mUidCounterSetMap: "
+ + getMapStatus(mUidCounterSetMap, UID_COUNTERSET_MAP_PATH));
+ pw.println("mAppUidStatsMap: " + getMapStatus(mAppUidStatsMap, APP_UID_STATS_MAP_PATH));
+ }
+
+ @GuardedBy("mStatsLock")
+ private void dumpCookieTagMapLocked(final IndentingPrintWriter pw) {
+ if (mCookieTagMap == null) {
+ return;
+ }
+ pw.println("mCookieTagMap:");
+ pw.increaseIndent();
+ try {
+ mCookieTagMap.forEach((key, value) -> {
+ // value could be null if there is a concurrent entry deletion.
+ // http://b/220084230.
+ if (value != null) {
+ pw.println("cookie=" + key.socketCookie
+ + " tag=0x" + Long.toHexString(value.tag)
+ + " uid=" + value.uid);
+ } else {
+ pw.println("Entry is deleted while dumping, iterating from first entry");
+ }
+ });
+ } catch (ErrnoException e) {
+ pw.println("mCookieTagMap dump end with error: " + Os.strerror(e.errno));
+ }
+ pw.decreaseIndent();
+ }
+
+ @GuardedBy("mStatsLock")
+ private void dumpUidCounterSetMapLocked(final IndentingPrintWriter pw) {
+ if (mUidCounterSetMap == null) {
+ return;
+ }
+ pw.println("mUidCounterSetMap:");
+ pw.increaseIndent();
+ try {
+ mUidCounterSetMap.forEach((uid, set) -> {
+ // set could be null if there is a concurrent entry deletion.
+ // http://b/220084230.
+ if (set != null) {
+ pw.println("uid=" + uid.val + " set=" + set.val);
+ } else {
+ pw.println("Entry is deleted while dumping, iterating from first entry");
+ }
+ });
+ } catch (ErrnoException e) {
+ pw.println("mUidCounterSetMap dump end with error: " + Os.strerror(e.errno));
+ }
+ pw.decreaseIndent();
+ }
+
+ @GuardedBy("mStatsLock")
+ private void dumpAppUidStatsMapLocked(final IndentingPrintWriter pw) {
+ if (mAppUidStatsMap == null) {
+ return;
+ }
+ pw.println("mAppUidStatsMap:");
+ pw.increaseIndent();
+ pw.println("uid rxBytes rxPackets txBytes txPackets");
+ try {
+ mAppUidStatsMap.forEach((key, value) -> {
+ // value could be null if there is a concurrent entry deletion.
+ // http://b/220084230.
+ if (value != null) {
+ pw.println(key.uid + " "
+ + value.rxBytes + " "
+ + value.rxPackets + " "
+ + value.txBytes + " "
+ + value.txPackets);
+ } else {
+ pw.println("Entry is deleted while dumping, iterating from first entry");
+ }
+ });
+ } catch (ErrnoException e) {
+ pw.println("mAppUidStatsMap dump end with error: " + Os.strerror(e.errno));
+ }
+ pw.decreaseIndent();
+ }
+
private NetworkStats readNetworkStatsSummaryDev() {
try {
return mStatsFactory.readNetworkStatsSummaryDev();
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 4dc056d..71329ad 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -173,13 +173,8 @@
RETURN_IF_NOT_OK(mIfaceStatsMap.init(IFACE_STATS_MAP_PATH));
RETURN_IF_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
- RETURN_IF_NOT_OK(
- mConfigurationMap.writeValue(UID_RULES_CONFIGURATION_KEY, DEFAULT_CONFIG, BPF_ANY));
- RETURN_IF_NOT_OK(mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY, SELECT_MAP_A,
- BPF_ANY));
RETURN_IF_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH));
- RETURN_IF_NOT_OK(mUidOwnerMap.clear());
RETURN_IF_NOT_OK(mUidPermissionMap.init(UID_PERMISSION_MAP_PATH));
ALOGI("%s successfully", __func__);
@@ -617,12 +612,6 @@
ScopedIndent indentPreBpfModule(dw);
dw.blankline();
- dw.println("mCookieTagMap status: %s",
- getMapStatus(mCookieTagMap.getMap(), COOKIE_TAG_MAP_PATH).c_str());
- dw.println("mUidCounterSetMap status: %s",
- getMapStatus(mUidCounterSetMap.getMap(), UID_COUNTERSET_MAP_PATH).c_str());
- dw.println("mAppUidStatsMap status: %s",
- getMapStatus(mAppUidStatsMap.getMap(), APP_UID_STATS_MAP_PATH).c_str());
dw.println("mStatsMapA status: %s",
getMapStatus(mStatsMapA.getMap(), STATS_MAP_A_PATH).c_str());
dw.println("mStatsMapB status: %s",
@@ -658,44 +647,6 @@
ScopedIndent indentForMapContent(dw);
- // Print CookieTagMap content.
- dumpBpfMap("mCookieTagMap", dw, "");
- const auto printCookieTagInfo = [&dw](const uint64_t& key, const UidTagValue& value,
- const BpfMap<uint64_t, UidTagValue>&) {
- dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", key, value.tag, value.uid);
- return base::Result<void>();
- };
- base::Result<void> res = mCookieTagMap.iterateWithValue(printCookieTagInfo);
- if (!res.ok()) {
- dw.println("mCookieTagMap print end with error: %s", res.error().message().c_str());
- }
-
- // Print UidCounterSetMap content.
- dumpBpfMap("mUidCounterSetMap", dw, "");
- const auto printUidInfo = [&dw](const uint32_t& key, const uint8_t& value,
- const BpfMap<uint32_t, uint8_t>&) {
- dw.println("%u %u", key, value);
- return base::Result<void>();
- };
- res = mUidCounterSetMap.iterateWithValue(printUidInfo);
- if (!res.ok()) {
- dw.println("mUidCounterSetMap print end with error: %s", res.error().message().c_str());
- }
-
- // Print AppUidStatsMap content.
- std::string appUidStatsHeader = StringPrintf("uid rxBytes rxPackets txBytes txPackets");
- dumpBpfMap("mAppUidStatsMap:", dw, appUidStatsHeader);
- auto printAppUidStatsInfo = [&dw](const uint32_t& key, const StatsValue& value,
- const BpfMap<uint32_t, StatsValue>&) {
- dw.println("%u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, key, value.rxBytes,
- value.rxPackets, value.txBytes, value.txPackets);
- return base::Result<void>();
- };
- res = mAppUidStatsMap.iterateWithValue(printAppUidStatsInfo);
- if (!res.ok()) {
- dw.println("mAppUidStatsMap print end with error: %s", res.error().message().c_str());
- }
-
// Print uidStatsMap content.
std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
" rxPackets txBytes txPackets");
@@ -712,7 +663,7 @@
value.rxPackets, value.txBytes, value.txPackets);
return base::Result<void>();
};
- res = mStatsMapA.iterateWithValue(printStatsInfo);
+ base::Result<void> res = mStatsMapA.iterateWithValue(printStatsInfo);
if (!res.ok()) {
dw.println("mStatsMapA print end with error: %s", res.error().message().c_str());
}
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index 7730c13..256a2a0 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -791,13 +791,6 @@
// ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets
// 999 test0 0x2a 10086 1 100 1 0 0
std::vector<std::string> expectedLines = {
- "mCookieTagMap:",
- fmt::format("cookie={} tag={:#x} uid={}", TEST_COOKIE, TEST_TAG, TEST_UID),
- "mUidCounterSetMap:",
- fmt::format("{} {}", TEST_UID3, TEST_COUNTERSET),
- "mAppUidStatsMap::", // TODO@: fix double colon
- "uid rxBytes rxPackets txBytes txPackets",
- fmt::format("{} {} {} {} {}", TEST_UID, RXBYTES, RXPACKETS, TXBYTES, TXPACKETS),
"mStatsMapA",
"ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes rxPackets txBytes txPackets",
fmt::format("{} {} {:#x} {} {} {} {} {} {}",
@@ -833,9 +826,6 @@
"Read value of map -1 failed: Bad file descriptor";
std::vector<std::string> expectedLines = {
- fmt::format("mCookieTagMap {}", kErrIterate),
- fmt::format("mUidCounterSetMap {}", kErrIterate),
- fmt::format("mAppUidStatsMap {}", kErrIterate),
fmt::format("mStatsMapA {}", kErrIterate),
fmt::format("mStatsMapB {}", kErrIterate),
fmt::format("mIfaceIndexNameMap {}", kErrIterate),
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 0270fc2..bedd0e8 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -87,6 +87,11 @@
private static final String UID_OWNER_MAP_PATH =
"/sys/fs/bpf/netd_shared/map_netd_uid_owner_map";
private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
+ private static final U32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new U32(1);
+ private static final long UID_RULES_DEFAULT_CONFIGURATION = 0;
+ private static final long STATS_SELECT_MAP_A = 0;
+ private static final long STATS_SELECT_MAP_B = 1;
+
private static BpfMap<U32, U32> sConfigurationMap = null;
// BpfMap for UID_OWNER_MAP_PATH. This map is not accessed by others.
private static BpfMap<U32, UidOwnerValue> sUidOwnerMap = null;
@@ -149,13 +154,31 @@
}
}
- private static void setBpfMaps() {
+ private static void initBpfMaps() {
if (sConfigurationMap == null) {
sConfigurationMap = getConfigurationMap();
}
+ try {
+ sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY,
+ new U32(UID_RULES_DEFAULT_CONFIGURATION));
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to initialize uid rules configuration", e);
+ }
+ try {
+ sConfigurationMap.updateEntry(CURRENT_STATS_MAP_CONFIGURATION_KEY,
+ new U32(STATS_SELECT_MAP_A));
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to initialize current stats configuration", e);
+ }
+
if (sUidOwnerMap == null) {
sUidOwnerMap = getUidOwnerMap();
}
+ try {
+ sUidOwnerMap.clear();
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to initialize uid owner map", e);
+ }
}
/**
@@ -171,7 +194,7 @@
}
Log.d(TAG, "BpfNetMaps is initialized with sEnableJavaBpfMap=" + sEnableJavaBpfMap);
- setBpfMaps();
+ initBpfMaps();
native_init();
sInitialized = true;
}
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 77dca95..c41484f 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -225,15 +225,13 @@
var inet6Addr: Inet6Address? = null
val timeout = SystemClock.elapsedRealtime() + PACKET_TIMEOUT_MS
+ val onLinkPrefix = raResponder.prefix
while (timeout > SystemClock.elapsedRealtime()) {
try {
// Pick any arbitrary port
Os.connect(sock, TEST_TARGET_IPV6_ADDR, 12345)
val sockAddr = Os.getsockname(sock) as InetSocketAddress
-
- // TODO: make RouterAdvertisementResponder.SLAAC_PREFIX public and use it here,
- // or make it configurable and configure it here.
- if (IpPrefix("2001:db8::/64").contains(sockAddr.address)) {
+ if (onLinkPrefix.contains(sockAddr.address)) {
inet6Addr = sockAddr.address as Inet6Address
break
}
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 484d717..18e074c 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.net;
+import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.app.usage.NetworkStatsManager.PREFIX_DEV;
@@ -156,7 +157,10 @@
import org.mockito.MockitoAnnotations;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Clock;
@@ -283,6 +287,7 @@
case PERMISSION_MAINLINE_NETWORK_STACK:
case READ_NETWORK_USAGE_HISTORY:
case UPDATE_DEVICE_STATS:
+ case DUMP:
return PERMISSION_GRANTED;
default:
return PERMISSION_DENIED;
@@ -2317,4 +2322,44 @@
assertTrue(mAppUidStatsMap.containsKey(new UidStatsMapKey(UID_RED)));
assertTrue(mUidCounterSetMap.containsKey(new U32(UID_RED)));
}
+
+ private void assertDumpContains(final String dump, final String message) {
+ assertTrue(String.format("dump(%s) does not contain '%s'", dump, message),
+ dump.contains(message));
+ }
+
+ private String getDump() {
+ final StringWriter sw = new StringWriter();
+ mService.dump(new FileDescriptor(), new PrintWriter(sw), new String[]{});
+ return sw.toString();
+ }
+
+ @Test
+ public void testDumpCookieTagMap() throws ErrnoException {
+ initBpfMapsWithTagData(UID_BLUE);
+
+ final String dump = getDump();
+ assertDumpContains(dump, "mCookieTagMap: OK");
+ assertDumpContains(dump, "cookie=2002 tag=0x1 uid=1002");
+ assertDumpContains(dump, "cookie=3002 tag=0x2 uid=1002");
+ }
+
+ @Test
+ public void testDumpUidCounterSetMap() throws ErrnoException {
+ initBpfMapsWithTagData(UID_BLUE);
+
+ final String dump = getDump();
+ assertDumpContains(dump, "mUidCounterSetMap: OK");
+ assertDumpContains(dump, "uid=1002 set=1");
+ }
+
+ @Test
+ public void testAppUidStatsMap() throws ErrnoException {
+ initBpfMapsWithTagData(UID_BLUE);
+
+ final String dump = getDump();
+ assertDumpContains(dump, "mAppUidStatsMap: OK");
+ assertDumpContains(dump, "uid rxBytes rxPackets txBytes txPackets");
+ assertDumpContains(dump, "1002 10000 10 6000 6");
+ }
}