Merge "Migrate bandwidth control to NMS, omit history."
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index ae9aa05..0548250 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -33,4 +33,7 @@
     /** Return usage summary per UID for traffic that matches template. */
     NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
 
+    /** Force update of statistics. */
+    void forceUpdate();
+
 }
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index ff6e220..dd2945c 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -279,10 +279,17 @@
         return (long) (start + (r.nextFloat() * (end - start)));
     }
 
-    public void dump(String prefix, PrintWriter pw) {
+    public void dump(String prefix, PrintWriter pw, boolean fullHistory) {
         pw.print(prefix);
         pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration);
-        for (int i = 0; i < bucketCount; i++) {
+
+        final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
+        if (start > 0) {
+            pw.print(prefix);
+            pw.print("  (omitting "); pw.print(start); pw.println(" buckets)");
+        }
+
+        for (int i = start; i < bucketCount; i++) {
             pw.print(prefix);
             pw.print("  bucketStart="); pw.print(bucketStart[i]);
             pw.print(" rx="); pw.print(rx[i]);
@@ -293,7 +300,7 @@
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
-        dump("", new PrintWriter(writer));
+        dump("", new PrintWriter(writer), false);
         return writer.toString();
     }
 
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index c9b6121..fcf4796 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -241,6 +241,4 @@
      */
     int getInterfaceTxThrottle(String iface);
 
-    void setBandwidthControlEnabled(boolean enabled);
-
 }
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index adc6570..1c150f8 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -16,10 +16,11 @@
 
 package com.android.server;
 
+import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
+import static android.provider.Settings.Secure.NETSTATS_ENABLED;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -35,6 +36,7 @@
 import android.os.INetworkManagementService;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -123,6 +125,8 @@
     /** Set of UIDs with active reject rules. */
     private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
 
+    private boolean mBandwidthControlEnabled;
+
     /**
      * Constructs a new NetworkManagementService instance
      *
@@ -161,6 +165,29 @@
         return new NetworkManagementService(context, procRoot);
     }
 
+    public void systemReady() {
+
+        // only enable bandwidth control when support exists, and requested by
+        // system setting.
+        // TODO: eventually migrate to be always enabled
+        final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
+        final boolean shouldEnable =
+                Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 0) != 0;
+
+        mBandwidthControlEnabled = false;
+        if (hasKernelSupport && shouldEnable) {
+            Slog.d(TAG, "enabling bandwidth control");
+            try {
+                mConnector.doCommand("bandwidth enable");
+                mBandwidthControlEnabled = true;
+            } catch (NativeDaemonConnectorException e) {
+                Slog.e(TAG, "problem enabling bandwidth controls", e);
+            }
+        } else {
+            Slog.d(TAG, "not enabling bandwidth control");
+        }
+    }
+
     public void registerObserver(INetworkManagementEventObserver obs) {
         Slog.d(TAG, "Registering observer");
         mObservers.add(obs);
@@ -919,7 +946,7 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
-        if (mProcStatsNetfilter.exists()) {
+        if (mBandwidthControlEnabled) {
             return getNetworkStatsDetailNetfilter(UID_ALL);
         } else {
             return getNetworkStatsDetailUidstat(UID_ALL);
@@ -930,6 +957,10 @@
     public void setInterfaceQuota(String iface, long quota) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
+        // silently discard when control disabled
+        // TODO: eventually migrate to be always enabled
+        if (!mBandwidthControlEnabled) return;
+
         synchronized (mInterfaceQuota) {
             if (mInterfaceQuota.contains(iface)) {
                 // TODO: eventually consider throwing
@@ -953,6 +984,10 @@
     public void removeInterfaceQuota(String iface) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
+        // silently discard when control disabled
+        // TODO: eventually migrate to be always enabled
+        if (!mBandwidthControlEnabled) return;
+
         synchronized (mInterfaceQuota) {
             if (!mInterfaceQuota.contains(iface)) {
                 // TODO: eventually consider throwing
@@ -976,6 +1011,10 @@
     public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
+        // silently discard when control disabled
+        // TODO: eventually migrate to be always enabled
+        if (!mBandwidthControlEnabled) return;
+
         synchronized (mUidRejectOnQuota) {
             final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
             if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
@@ -1011,7 +1050,7 @@
                     android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
         }
 
-        if (mProcStatsNetfilter.exists()) {
+        if (mBandwidthControlEnabled) {
             return getNetworkStatsDetailNetfilter(uid);
         } else {
             return getNetworkStatsDetailUidstat(uid);
@@ -1151,12 +1190,6 @@
         return getInterfaceThrottle(iface, false);
     }
 
-    @Override
-    public void setBandwidthControlEnabled(boolean enabled) {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-        mConnector.doCommand(String.format("bandwidth %s", (enabled ? "enable" : "disable")));
-    }
-
     /**
      * Split given line into {@link ArrayList}.
      */
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index dbfd145..8c7e279 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -523,6 +523,7 @@
         // These are needed to propagate to the runnable below.
         final Context contextF = context;
         final BatteryService batteryF = battery;
+        final NetworkManagementService networkManagementF = networkManagement;
         final NetworkStatsService networkStatsF = networkStats;
         final NetworkPolicyManagerService networkPolicyF = networkPolicy;
         final ConnectivityService connectivityF = connectivity;
@@ -550,6 +551,7 @@
 
                 startSystemUi(contextF);
                 if (batteryF != null) batteryF.systemReady();
+                if (networkManagementF != null) networkManagementF.systemReady();
                 if (networkStatsF != null) networkStatsF.systemReady();
                 if (networkPolicyF != null) networkPolicyF.systemReady();
                 if (connectivityF != null) connectivityF.systemReady();
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 1f2ec2c..2a17cbe 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1044,8 +1044,11 @@
 
         // TODO: only dispatch when rules actually change
 
-        // record rule locally to dispatch to new listeners
-        mUidRules.put(uid, uidRules);
+        if (uidRules == RULE_ALLOW_ALL) {
+            mUidRules.delete(uid);
+        } else {
+            mUidRules.put(uid, uidRules);
+        }
 
         final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
         setUidNetworkRules(uid, rejectMetered);
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 7610a11..b4bd176 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -134,7 +134,6 @@
      * Settings that can be changed externally.
      */
     public interface NetworkStatsSettings {
-        public boolean getEnabled();
         public long getPollInterval();
         public long getPersistThreshold();
         public long getNetworkBucketDuration();
@@ -207,20 +206,6 @@
     }
 
     public void systemReady() {
-        if (mSettings.getEnabled()) {
-            try {
-                // enable low-level bandwidth stats and control
-                // TODO: consider shipping with this enabled by default
-                mNetworkManager.setBandwidthControlEnabled(true);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "problem talking to netd while enabling bandwidth controls", e);
-            } catch (NativeDaemonConnectorException ndce) {
-                Slog.e(TAG, "problem enabling bandwidth controls", ndce);
-            }
-        } else {
-            Slog.w(TAG, "detailed network stats disabled");
-        }
-
         synchronized (mStatsLock) {
             // read historical network stats from disk, since policy service
             // might need them right away. we delay loading detailed UID stats
@@ -389,6 +374,15 @@
         }
     }
 
+    @Override
+    public void forceUpdate() {
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+
+        synchronized (mStatsLock) {
+            performPollLocked(true, false);
+        }
+    }
+
     /**
      * Receiver that watches for {@link IConnectivityManager} to claim network
      * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
@@ -905,6 +899,8 @@
             argSet.add(arg);
         }
 
+        final boolean fullHistory = argSet.contains("full");
+
         synchronized (mStatsLock) {
             // TODO: remove this testing code, since it corrupts stats
             if (argSet.contains("generate")) {
@@ -930,7 +926,7 @@
             for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
                 final NetworkStatsHistory history = mNetworkStats.get(ident);
                 pw.print("  ident="); pw.println(ident.toString());
-                history.dump("  ", pw);
+                history.dump("  ", pw, fullHistory);
             }
 
             if (argSet.contains("detail")) {
@@ -950,7 +946,7 @@
                         final NetworkStatsHistory history = uidStats.valueAt(i);
                         pw.print("    UID="); pw.print(uid);
                         pw.print(" tag="); pw.println(tag);
-                        history.dump("    ", pw);
+                        history.dump("    ", pw, fullHistory);
                     }
                 }
             }
@@ -1058,15 +1054,6 @@
             return Settings.Secure.getLong(mResolver, name, def);
         }
 
-        public boolean getEnabled() {
-            if (!new File("/proc/net/xt_qtaguid/ctrl").exists()) {
-                Slog.w(TAG, "kernel does not support bandwidth control");
-                return false;
-            }
-            // TODO: once things stabilize, enable by default.
-            // For now: ./vendor/google/tools/override-gservices secure:netstats_enabled=1
-            return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 0) != 0;
-        }
         public long getPollInterval() {
             return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
         }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 903f2b0..f2c28bb 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -610,9 +610,6 @@
         mAlarmManager.setInexactRepeating(
                 eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class));
         expectLastCall().atLeastOnce();
-
-        mNetManager.setBandwidthControlEnabled(true);
-        expectLastCall().atLeastOnce();
     }
 
     private void expectNetworkState(NetworkState... state) throws Exception {
@@ -633,7 +630,6 @@
 
     private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory)
             throws Exception {
-        expect(mSettings.getEnabled()).andReturn(true).anyTimes();
         expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
         expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes();
         expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes();