Merge "No-op refactoring for TrafficStats APIs" into main am: 05fb57ea97 am: 0bc4d4ea5e

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/3249945

Change-Id: I63399df538e64396dbbf00efbb9e8fc82118985a
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl
index 7f0c1fe..01ac106 100644
--- a/framework-t/src/android/net/INetworkStatsService.aidl
+++ b/framework-t/src/android/net/INetworkStatsService.aidl
@@ -78,13 +78,16 @@
     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 77c8001..3b6a69b 100644
--- a/framework-t/src/android/net/TrafficStats.java
+++ b/framework-t/src/android/net/TrafficStats.java
@@ -40,6 +40,9 @@
 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 @@
      * @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 @@
      * @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 @@
      * @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 @@
      * @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 @@
      * 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 @@
      * 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 @@
      * 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 @@
      * 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 @@
      * @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 @@
      * @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 @@
      * @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 @@
      * @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 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<NetworkStats.Entry> 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 9b7af49..0d27d54 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_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 @@
 
     @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 @@
         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.");
+        NetworkStats stats = new NetworkStats(0, 0);
+        if (entry != null) {
+            stats.insertEntry(entry);
         }
-    }
-
-    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;
-        }
+        return stats;
     }
 
     @Nullable
@@ -2221,18 +2199,22 @@
         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 0000000..c61541e
--- /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 3d2f389..9cf6007 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.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 @@
     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,