diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl index 7f0c1fe6cc..01ac10681a 100644 --- a/framework-t/src/android/net/INetworkStatsService.aidl +++ b/framework-t/src/android/net/INetworkStatsService.aidl @@ -78,13 +78,16 @@ interface INetworkStatsService { void unregisterUsageRequest(in DataUsageRequest request); /** Get the uid stats information since boot */ - long getUidStats(int uid, int type); + NetworkStats getTypelessUidStats(int uid); /** Get the iface stats information since boot */ - long getIfaceStats(String iface, int type); + NetworkStats getTypelessIfaceStats(String iface); /** Get the total network stats information since boot */ - long getTotalStats(int type); + NetworkStats getTypelessTotalStats(); + + /** Get the uid stats information (with specified type) since boot */ + long getUidStats(int uid, int type); /** Registers a network stats provider */ INetworkStatsProviderCallback registerNetworkStatsProvider(String tag, diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index 77c8001630..3b6a69bb33 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -40,6 +40,9 @@ import java.io.IOException; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; +import java.util.Iterator; +import java.util.Objects; + /** * Class that provides network traffic statistics. These statistics include @@ -730,11 +733,7 @@ public class TrafficStats { * @return The number of transmitted packets. */ public static long getTxPackets(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(iface, TYPE_TX_PACKETS); } /** @@ -753,11 +752,7 @@ public class TrafficStats { * @return The number of received packets. */ public static long getRxPackets(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(iface, TYPE_RX_PACKETS); } /** @@ -776,11 +771,7 @@ public class TrafficStats { * @return The number of transmitted bytes. */ public static long getTxBytes(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(iface, TYPE_TX_BYTES); } /** @@ -799,51 +790,31 @@ public class TrafficStats { * @return The number of received bytes. */ public static long getRxBytes(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(iface, TYPE_RX_BYTES); } /** {@hide} */ @TestApi public static long getLoopbackTxPackets() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS); } /** {@hide} */ @TestApi public static long getLoopbackRxPackets() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS); } /** {@hide} */ @TestApi public static long getLoopbackTxBytes() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES); } /** {@hide} */ @TestApi public static long getLoopbackRxBytes() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES); } /** @@ -856,11 +827,7 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalTxPackets() { - try { - return getStatsService().getTotalStats(TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTotalStats(TYPE_TX_PACKETS); } /** @@ -873,11 +840,7 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalRxPackets() { - try { - return getStatsService().getTotalStats(TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTotalStats(TYPE_RX_PACKETS); } /** @@ -890,11 +853,7 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalTxBytes() { - try { - return getStatsService().getTotalStats(TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTotalStats(TYPE_TX_BYTES); } /** @@ -907,11 +866,7 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalRxBytes() { - try { - return getStatsService().getTotalStats(TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getTotalStats(TYPE_RX_BYTES); } /** @@ -933,11 +888,7 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxBytes(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getUidStats(uid, TYPE_TX_BYTES); } /** @@ -959,11 +910,7 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxBytes(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getUidStats(uid, TYPE_RX_BYTES); } /** @@ -985,11 +932,7 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxPackets(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return getUidStats(uid, TYPE_TX_PACKETS); } /** @@ -1011,11 +954,50 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxPackets(int uid) { + return getUidStats(uid, TYPE_RX_PACKETS); + } + + /** @hide */ + public static long getUidStats(int uid, int type) { + if (!isEntryValueTypeValid(type) + || android.os.Process.myUid() != uid) { + return UNSUPPORTED; + } + final NetworkStats stats; try { - return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); + stats = getStatsService().getTypelessUidStats(uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + return getValueForTypeFromFirstEntry(stats, type); + } + + /** @hide */ + public static long getTotalStats(int type) { + if (!isEntryValueTypeValid(type)) { + return UNSUPPORTED; + } + final NetworkStats stats; + try { + stats = getStatsService().getTypelessTotalStats(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return getValueForTypeFromFirstEntry(stats, type); + } + + /** @hide */ + public static long getIfaceStats(String iface, int type) { + if (!isEntryValueTypeValid(type)) { + return UNSUPPORTED; + } + final NetworkStats stats; + try { + stats = getStatsService().getTypelessIfaceStats(iface); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return getValueForTypeFromFirstEntry(stats, type); } /** @@ -1143,4 +1125,45 @@ public class TrafficStats { public static final int TYPE_TX_BYTES = 2; /** {@hide} */ public static final int TYPE_TX_PACKETS = 3; + + /** @hide */ + private static long getEntryValueForType(@NonNull NetworkStats.Entry entry, int type) { + Objects.requireNonNull(entry); + if (!isEntryValueTypeValid(type)) return UNSUPPORTED; + switch (type) { + case TYPE_RX_BYTES: + return entry.getRxBytes(); + case TYPE_RX_PACKETS: + return entry.getRxPackets(); + case TYPE_TX_BYTES: + return entry.getTxBytes(); + case TYPE_TX_PACKETS: + return entry.getTxPackets(); + default: + throw new IllegalStateException("Bug: Invalid type: " + + type + " should not reach here."); + } + } + + /** @hide */ + private static boolean isEntryValueTypeValid(int type) { + switch (type) { + case TYPE_RX_BYTES: + case TYPE_RX_PACKETS: + case TYPE_TX_BYTES: + case TYPE_TX_PACKETS: + return true; + default : + return false; + } + } + + /** @hide */ + public static long getValueForTypeFromFirstEntry(@NonNull NetworkStats stats, int type) { + Objects.requireNonNull(stats); + Iterator iter = stats.iterator(); + if (!iter.hasNext()) return UNSUPPORTED; + return getEntryValueForType(iter.next(), type); + } } + diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 9b7af49b80..0d27d54a50 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -51,12 +51,8 @@ import static android.net.NetworkTemplate.MATCH_TEST; import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; -import static android.net.TrafficStats.TYPE_RX_BYTES; -import static android.net.TrafficStats.TYPE_RX_PACKETS; -import static android.net.TrafficStats.TYPE_TX_BYTES; -import static android.net.TrafficStats.TYPE_TX_PACKETS; import static android.net.TrafficStats.UID_TETHERING; -import static android.net.TrafficStats.UNSUPPORTED; +import static android.net.TrafficStats.getValueForTypeFromFirstEntry; import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; @@ -2135,20 +2131,28 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getUidStats(int uid, int type) { + return getValueForTypeFromFirstEntry(getTypelessUidStats(uid), type); + } + + @NonNull + @Override + public NetworkStats getTypelessUidStats(int uid) { + final NetworkStats stats = new NetworkStats(0, 0); final int callingUid = Binder.getCallingUid(); if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) { - return UNSUPPORTED; + return stats; } - if (!isEntryValueTypeValid(type)) return UNSUPPORTED; - + final NetworkStats.Entry entry; if (mAlwaysUseTrafficStatsRateLimitCache || mDeps.isChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, callingUid)) { - final NetworkStats.Entry entry = mTrafficStatsUidCache.getOrCompute(IFACE_ALL, uid, + entry = mTrafficStatsUidCache.getOrCompute(IFACE_ALL, uid, () -> mDeps.nativeGetUidStat(uid)); - return getEntryValueForType(entry, type); - } + } else entry = mDeps.nativeGetUidStat(uid); - return getEntryValueForType(mDeps.nativeGetUidStat(uid), type); + if (entry != null) { + stats.insertEntry(entry); + } + return stats; } @Nullable @@ -2165,50 +2169,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return entry; } + @NonNull @Override - public long getIfaceStats(@NonNull String iface, int type) { + public NetworkStats getTypelessIfaceStats(@NonNull String iface) { Objects.requireNonNull(iface); - if (!isEntryValueTypeValid(type)) return UNSUPPORTED; + final NetworkStats.Entry entry; if (mAlwaysUseTrafficStatsRateLimitCache || mDeps.isChangeEnabled( ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, Binder.getCallingUid())) { - final NetworkStats.Entry entry = mTrafficStatsIfaceCache.getOrCompute(iface, UID_ALL, + entry = mTrafficStatsIfaceCache.getOrCompute(iface, UID_ALL, () -> getIfaceStatsInternal(iface)); - return getEntryValueForType(entry, type); - } + } else entry = getIfaceStatsInternal(iface); - return getEntryValueForType(getIfaceStatsInternal(iface), type); - } - - private long getEntryValueForType(@Nullable NetworkStats.Entry entry, int type) { - if (entry == null) return UNSUPPORTED; - if (!isEntryValueTypeValid(type)) return UNSUPPORTED; - switch (type) { - case TYPE_RX_BYTES: - return entry.rxBytes; - case TYPE_RX_PACKETS: - return entry.rxPackets; - case TYPE_TX_BYTES: - return entry.txBytes; - case TYPE_TX_PACKETS: - return entry.txPackets; - default: - throw new IllegalStateException("Bug: Invalid type: " - + type + " should not reach here."); - } - } - - private boolean isEntryValueTypeValid(int type) { - switch (type) { - case TYPE_RX_BYTES: - case TYPE_RX_PACKETS: - case TYPE_TX_BYTES: - case TYPE_TX_PACKETS: - return true; - default : - return false; + NetworkStats stats = new NetworkStats(0, 0); + if (entry != null) { + stats.insertEntry(entry); } + return stats; } @Nullable @@ -2221,18 +2199,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return entry; } + @NonNull @Override - public long getTotalStats(int type) { - if (!isEntryValueTypeValid(type)) return UNSUPPORTED; + public NetworkStats getTypelessTotalStats() { + final NetworkStats.Entry entry; if (mAlwaysUseTrafficStatsRateLimitCache || mDeps.isChangeEnabled( ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, Binder.getCallingUid())) { - final NetworkStats.Entry entry = mTrafficStatsTotalCache.getOrCompute( + entry = mTrafficStatsTotalCache.getOrCompute( IFACE_ALL, UID_ALL, () -> getTotalStatsInternal()); - return getEntryValueForType(entry, type); - } + } else entry = getTotalStatsInternal(); - return getEntryValueForType(getTotalStatsInternal(), type); + final NetworkStats stats = new NetworkStats(0, 0); + if (entry != null) { + stats.insertEntry(entry); + } + return stats; } @Override diff --git a/tests/unit/java/android/net/TrafficStatsTest.kt b/tests/unit/java/android/net/TrafficStatsTest.kt new file mode 100644 index 0000000000..c61541e34f --- /dev/null +++ b/tests/unit/java/android/net/TrafficStatsTest.kt @@ -0,0 +1,46 @@ +/* +* Copyright (C) 2024 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package android.net + +import android.net.TrafficStats.getValueForTypeFromFirstEntry +import android.net.TrafficStats.TYPE_RX_BYTES +import android.net.TrafficStats.UNSUPPORTED +import android.os.Build +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals + +private const val TEST_IFACE1 = "test_iface1" + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) +class TrafficStatsTest { + + @Test + fun testGetValueForTypeFromFirstEntry() { + var stats: NetworkStats = NetworkStats(0, 0) + // empty stats + assertEquals(getValueForTypeFromFirstEntry(stats, TYPE_RX_BYTES), UNSUPPORTED.toLong()) + // invalid type + stats.insertEntry(TEST_IFACE1, 1, 2, 3, 4) + assertEquals(getValueForTypeFromFirstEntry(stats, 1000), UNSUPPORTED.toLong()) + // valid type + assertEquals(getValueForTypeFromFirstEntry(stats, TYPE_RX_BYTES), 1) + } +} \ No newline at end of file diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java index 3d2f38947d..9cf60074ab 100644 --- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java @@ -56,6 +56,7 @@ import static android.net.NetworkTemplate.OEM_MANAGED_YES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; +import static android.net.TrafficStats.getValueForTypeFromFirstEntry; import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; @@ -2514,11 +2515,13 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { private void assertTrafficStatsValues(String iface, int uid, long rxBytes, long rxPackets, long txBytes, long txPackets) { assertTrafficStatsValuesThat(rxBytes, rxPackets, txBytes, txPackets, - (type) -> mService.getTotalStats(type)); + (type) -> getValueForTypeFromFirstEntry(mService.getTypelessTotalStats(), type)); assertTrafficStatsValuesThat(rxBytes, rxPackets, txBytes, txPackets, - (type) -> mService.getIfaceStats(iface, type)); + (type) -> getValueForTypeFromFirstEntry( + mService.getTypelessIfaceStats(iface), type) + ); assertTrafficStatsValuesThat(rxBytes, rxPackets, txBytes, txPackets, - (type) -> mService.getUidStats(uid, type)); + (type) -> getValueForTypeFromFirstEntry(mService.getTypelessUidStats(uid), type)); } private void assertTrafficStatsValuesThat(long rxBytes, long rxPackets, long txBytes,