From 350083e36b9db6062e165954403ef921ff3dfdad Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 29 Jun 2011 10:45:16 -0700 Subject: [PATCH] Migrate bandwidth control to NMS, omit history. Both stats and policy make NMS calls that depend on bandwidth control being enabled, so move enable/disable into NMS and drop calls when disabled. This avoids throwing heavy ISE exceptions when disabled. Only include recent data when writing NetworkStatsHistory as part of dumpsys call. Introduce manual poll event for Settings UI. Bug: 4982115, 4770435, 4515856 Change-Id: I257820b057af2f0f99c736fb4f61e55b9fdc3e66 --- .../android/net/INetworkStatsService.aidl | 3 ++ .../java/android/net/NetworkStatsHistory.java | 13 +++-- .../android/os/INetworkManagementService.aidl | 2 - .../server/NetworkManagementService.java | 51 +++++++++++++++---- .../java/com/android/server/SystemServer.java | 2 + .../net/NetworkPolicyManagerService.java | 7 ++- .../server/net/NetworkStatsService.java | 39 +++++--------- .../server/NetworkStatsServiceTest.java | 4 -- 8 files changed, 75 insertions(+), 46 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index ae9aa05e0bce4..054825024b9af 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -33,4 +33,7 @@ interface INetworkStatsService { /** 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 ff6e220cac41b..dd2945ca18af5 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -279,10 +279,17 @@ public class NetworkStatsHistory implements Parcelable { 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 @@ public class NetworkStatsHistory implements Parcelable { @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 c9b6121adcf96..fcf479631b038 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -241,6 +241,4 @@ interface INetworkManagementService */ 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 adc65708d5ef4..1c150f8a65eac 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.Binder; 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 @@ class NetworkManagementService extends INetworkManagementService.Stub { /** Set of UIDs with active reject rules. */ private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray(); + private boolean mBandwidthControlEnabled; + /** * Constructs a new NetworkManagementService instance * @@ -161,6 +165,29 @@ class NetworkManagementService extends INetworkManagementService.Stub { 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 @@ class NetworkManagementService extends INetworkManagementService.Stub { 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 @@ class NetworkManagementService extends INetworkManagementService.Stub { 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 @@ class NetworkManagementService extends INetworkManagementService.Stub { 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 @@ class NetworkManagementService extends INetworkManagementService.Stub { 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 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); } - if (mProcStatsNetfilter.exists()) { + if (mBandwidthControlEnabled) { return getNetworkStatsDetailNetfilter(uid); } else { return getNetworkStatsDetailUidstat(uid); @@ -1151,12 +1190,6 @@ class NetworkManagementService extends INetworkManagementService.Stub { 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 dbfd145bc65f8..8c7e279b71329 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -523,6 +523,7 @@ class ServerThread extends Thread { // 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 @@ class ServerThread extends Thread { 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 1f2ec2ca82796..2a17cbe7afda4 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -1044,8 +1044,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // 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 7610a1181d60a..b4bd176906054 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -134,7 +134,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * 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 class NetworkStatsService extends INetworkStatsService.Stub { } 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 903f2b0b6f668..f2c28bb538c8c 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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 @@ public class NetworkStatsServiceTest extends AndroidTestCase { 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();