OSDN Git Service

Ask netd to swap stats map before reading
authorChenbo Feng <fengc@google.com>
Thu, 28 Feb 2019 03:07:39 +0000 (19:07 -0800)
committerChenbo Feng <fengc@google.com>
Wed, 10 Apr 2019 19:59:38 +0000 (12:59 -0700)
To avoid protentail race problem between netd and system_server when
reading the network stats map. Always inform netd before reading the
stats and let netd to do a swap between active stats map and inactive
stats map. So the system_server can safely remove the stats after
reading.

Bug: 126620214
Test: android.app.usage.cts.NetworkUsageStatsTest
      android.net.cts.TrafficStatsTest

Change-Id: I8fa37c26bec23ffca0b29b679e72ba1189f557f1

services/core/java/com/android/server/net/NetworkStatsFactory.java

index bd11d46..2e64965 100644 (file)
@@ -24,7 +24,10 @@ import static android.net.NetworkStats.UID_ALL;
 import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
 
 import android.annotation.Nullable;
+import android.net.INetd;
 import android.net.NetworkStats;
+import android.net.util.NetdService;
+import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.SystemClock;
 
@@ -65,6 +68,8 @@ public class NetworkStatsFactory {
 
     private boolean mUseBpfStats;
 
+    private INetd mNetdService;
+
     // A persistent Snapshot since device start for eBPF stats
     @GuardedBy("mPersistSnapshot")
     private final NetworkStats mPersistSnapshot;
@@ -279,6 +284,19 @@ public class NetworkStatsFactory {
         return stats;
     }
 
+    @GuardedBy("mPersistSnapshot")
+    private void requestSwapActiveStatsMapLocked() throws RemoteException {
+        // Ask netd to do a active map stats swap. When the binder call successfully returns,
+        // the system server should be able to safely read and clean the inactive map
+        // without race problem.
+        if (mUseBpfStats) {
+            if (mNetdService == null) {
+                mNetdService = NetdService.getInstance();
+            }
+            mNetdService.trafficSwapActiveStatsMap();
+        }
+    }
+
     // TODO: delete the lastStats parameter
     private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces,
             int limitTag, NetworkStats lastStats) throws IOException {
@@ -292,6 +310,13 @@ public class NetworkStatsFactory {
             }
             if (mUseBpfStats) {
                 synchronized (mPersistSnapshot) {
+                    try {
+                        requestSwapActiveStatsMapLocked();
+                    } catch (RemoteException e) {
+                        throw new IOException(e);
+                    }
+                    // Stats are always read from the inactive map, so they must be read after the
+                    // swap
                     if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
                             null, TAG_ALL, mUseBpfStats) != 0) {
                         throw new IOException("Failed to parse network stats");