Merge "Allowing for null net caps in updateConfiguration"
diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java
index a8baa8e..ca080ce 100644
--- a/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -744,8 +744,9 @@
      * {@link #unregisterUsageCallback} is called.
      *
      * @param template Template used to match networks. See {@link NetworkTemplate}.
-     * @param thresholdBytes Threshold in bytes to be notified on. The provided value that lower
-     *                       than 2MiB will be clamped for non-privileged callers.
+     * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB
+     *                       will be clamped for callers except callers with the NETWORK_STACK
+     *                       permission.
      * @param executor The executor on which callback will be invoked. The provided {@link Executor}
      *                 must run callback sequentially, otherwise the order of callbacks cannot be
      *                 guaranteed.
@@ -754,6 +755,9 @@
      * @hide
      */
     @SystemApi(client = MODULE_LIBRARIES)
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK}, conditional = true)
     public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes,
             @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) {
         Objects.requireNonNull(template, "NetworkTemplate cannot be null");
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java
index 151c90d..3b93f1a 100644
--- a/service-t/src/com/android/server/net/NetworkStatsFactory.java
+++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -25,9 +25,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.net.ConnectivityManager;
 import android.net.NetworkStats;
 import android.net.UnderlyingNetworkInfo;
+import android.os.ServiceSpecificException;
 import android.os.StrictMode;
 import android.os.SystemClock;
 
@@ -35,6 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ProcFileReader;
 import com.android.net.module.util.CollectionUtils;
+import com.android.server.BpfNetMaps;
 
 import libcore.io.IoUtils;
 
@@ -74,6 +75,8 @@
 
     private final Context mContext;
 
+    private final BpfNetMaps mBpfNetMaps;
+
     /**
      * Guards persistent data access in this class
      *
@@ -170,6 +173,7 @@
         mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
         mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
         mUseBpfStats = useBpfStats;
+        mBpfNetMaps = new BpfNetMaps();
         synchronized (mPersistentDataLock) {
             mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
             mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
@@ -297,12 +301,14 @@
     }
 
     @GuardedBy("mPersistentDataLock")
-    private void requestSwapActiveStatsMapLocked() {
-        // 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.
-        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
-        cm.swapActiveStatsMap();
+    private void requestSwapActiveStatsMapLocked() throws IOException {
+        try {
+            // Do a active map stats swap. Once the swap completes, this code
+            // can read and clean the inactive map without races.
+            mBpfNetMaps.swapActiveStatsMap();
+        } catch (ServiceSpecificException e) {
+            throw new IOException(e);
+        }
     }
 
     /**
@@ -328,11 +334,7 @@
                 final NetworkStats stats =
                         new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */);
                 if (mUseBpfStats) {
-                    try {
-                        requestSwapActiveStatsMapLocked();
-                    } catch (RuntimeException e) {
-                        throw new IOException(e);
-                    }
+                    requestSwapActiveStatsMapLocked();
                     // Stats are always read from the inactive map, so they must be read after the
                     // swap
                     if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java
index 1953624..fdfc893 100644
--- a/service-t/src/com/android/server/net/NetworkStatsObservers.java
+++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java
@@ -19,8 +19,11 @@
 import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES;
 
 import android.app.usage.NetworkStatsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.DataUsageRequest;
 import android.net.NetworkIdentitySet;
+import android.net.NetworkStack;
 import android.net.NetworkStats;
 import android.net.NetworkStatsAccess;
 import android.net.NetworkStatsCollection;
@@ -74,9 +77,9 @@
      *
      * @return the normalized request wrapped within {@link RequestInfo}.
      */
-    public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback,
-            int callingUid, @NetworkStatsAccess.Level int accessLevel) {
-        DataUsageRequest request = buildRequest(inputRequest, callingUid);
+    public DataUsageRequest register(Context context, DataUsageRequest inputRequest,
+            IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
+        DataUsageRequest request = buildRequest(context, inputRequest, callingUid);
         RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid,
                 accessLevel);
 
@@ -194,10 +197,13 @@
         }
     }
 
-    private DataUsageRequest buildRequest(DataUsageRequest request, int callingUid) {
-        // For non-system uid, cap the minimum threshold to a safe default to avoid too
-        // many callbacks.
-        long thresholdInBytes = (callingUid == Process.SYSTEM_UID ? request.thresholdInBytes
+    private DataUsageRequest buildRequest(Context context, DataUsageRequest request,
+                int callingUid) {
+        // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to
+        // avoid too many callbacks.
+        final long thresholdInBytes = (context.checkPermission(
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid)
+                == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes
                 : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes));
         if (thresholdInBytes > request.thresholdInBytes) {
             Log.w(TAG, "Threshold was too low for " + request
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index fae7aeb..f835581 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -565,7 +565,7 @@
                 return new BpfMap<U32, U8>(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR,
                         U32.class, U8.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create uid counter set map: " + e);
+                Log.wtf(TAG, "Cannot open uid counter set map: " + e);
                 return null;
             }
         }
@@ -576,7 +576,7 @@
                 return new BpfMap<CookieTagMapKey, CookieTagMapValue>(COOKIE_TAG_MAP_PATH,
                         BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create cookie tag map: " + e);
+                Log.wtf(TAG, "Cannot open cookie tag map: " + e);
                 return null;
             }
         }
@@ -587,7 +587,7 @@
                 return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_A_PATH,
                         BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create stats map A: " + e);
+                Log.wtf(TAG, "Cannot open stats map A: " + e);
                 return null;
             }
         }
@@ -598,7 +598,7 @@
                 return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_B_PATH,
                         BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create stats map B: " + e);
+                Log.wtf(TAG, "Cannot open stats map B: " + e);
                 return null;
             }
         }
@@ -609,7 +609,7 @@
                 return new BpfMap<UidStatsMapKey, StatsMapValue>(APP_UID_STATS_MAP_PATH,
                         BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class);
             } catch (ErrnoException e) {
-                Log.wtf(TAG, "Cannot create app uid stats map: " + e);
+                Log.wtf(TAG, "Cannot open app uid stats map: " + e);
                 return null;
             }
         }
@@ -1285,7 +1285,7 @@
         DataUsageRequest normalizedRequest;
         final long token = Binder.clearCallingIdentity();
         try {
-            normalizedRequest = mStatsObservers.register(
+            normalizedRequest = mStatsObservers.register(mContext,
                     request, callback, callingUid, accessLevel);
         } finally {
             Binder.restoreCallingIdentity(token);