Push interface quota rules from NetworkPolicyManager to kernel.

Change-Id: Id2b758f561820b44839f69bf5fbd676cae771fe3
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 630aaf9..634a3f2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -921,6 +921,38 @@
     }
 
     @Override
+    public void setInterfaceQuota(String[] iface, long quota)
+            throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_NETWORK_POLICY, "NetworkManagementService");
+        try {
+            // TODO: Add support for clubbing together multiple interfaces under
+            // one quota. Will need support from the kernel and
+            // BandwidthController to do this.
+            mConnector.doCommand(
+                    String.format("bandwidth setquota %s %d", iface[0], quota));
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Error communicating to native daemon to set Interface quota",
+                    e);
+        }
+    }
+
+    @Override
+    public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
+            throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_NETWORK_POLICY, "NetworkManagementService");
+        try {
+            // TODO: Connect with BandwidthController
+            // mConnector.doCommand("");
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Error communicating to native daemon to set Interface quota",
+                    e);
+        }
+    }
+
     public NetworkStats getNetworkStatsUidDetail(int uid) {
         if (Binder.getCallingUid() != uid) {
             mContext.enforceCallingOrSelfPermission(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd68c68..dbfd145 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -283,7 +283,8 @@
             try {
                 Slog.i(TAG, "NetworkPolicy Service");
                 networkPolicy = new NetworkPolicyManagerService(
-                        context, ActivityManagerService.self(), power, networkStats);
+                        context, ActivityManagerService.self(), power,
+                        networkStats, networkManagement);
                 ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
             } catch (Throwable e) {
                 Slog.e(TAG, "Failure starting NetworkPolicy Service", e);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 12d3ed8..8a93f43 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -71,6 +71,7 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.Message;
 import android.os.RemoteCallbackList;
@@ -156,6 +157,7 @@
     private final IActivityManager mActivityManager;
     private final IPowerManager mPowerManager;
     private final INetworkStatsService mNetworkStats;
+    private final INetworkManagementService mNetworkManagement;
     private final TrustedTime mTime;
 
     private IConnectivityManager mConnManager;
@@ -193,9 +195,11 @@
     // rules enforced, such as system, phone, and radio UIDs.
 
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
-            IPowerManager powerManager, INetworkStatsService networkStats) {
+            IPowerManager powerManager, INetworkStatsService networkStats,
+            INetworkManagementService networkManagement) {
         // TODO: move to using cached NtpTrustedTime
-        this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
+        this(context, activityManager, powerManager, networkStats,
+                networkManagement, new NtpTrustedTime(),
                 getSystemDir());
     }
 
@@ -204,12 +208,14 @@
     }
 
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
-            IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
-            File systemDir) {
+            IPowerManager powerManager, INetworkStatsService networkStats,
+            INetworkManagementService networkManagement,
+            TrustedTime time, File systemDir) {
         mContext = checkNotNull(context, "missing context");
         mActivityManager = checkNotNull(activityManager, "missing activityManager");
         mPowerManager = checkNotNull(powerManager, "missing powerManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
+        mNetworkManagement = checkNotNull(networkManagement, "missing networkManagementService");
         mTime = checkNotNull(time, "missing TrustedTime");
 
         mHandlerThread = new HandlerThread(TAG);
@@ -589,7 +595,13 @@
             if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
                 // remaining "quota" is based on usage in current cycle
                 final long quota = Math.max(0, policy.limitBytes - total);
-                //kernelSetIfacesQuota(ifaces, quota);
+                if (LOGD) {
+                    Slog.d(TAG, "Applying quota rules for ifaces=" + Arrays.toString(ifaces)
+                            + " LIMIT=" + policy.limitBytes + "  TOTAL="
+                            + total + "  QUOTA=" + quota);
+                }
+
+                setQuotaOnIfaceList(ifaces, quota);
 
                 for (String iface : ifaces) {
                     mMeteredIfaces.add(iface);
@@ -601,6 +613,32 @@
         mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
     }
 
+    private void setQuotaOnIfaceList(String[] ifaces, long quota) {
+        try {
+            mNetworkManagement.setInterfaceQuota(ifaces, quota);
+        } catch (IllegalStateException e) {
+            Slog.e(TAG, "IllegalStateException in setQuotaOnIfaceList " + e);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote Exception in setQuotaOnIfaceList " + e);
+        }
+    }
+
+    private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+        // TODO: connect over to NMS
+        // ndc bandwidth app <uid> naughty
+        try {
+            if (LOGD) {
+                Slog.d(TAG, "setUidNetworkRules() with uid=" + uid
+                        + ", rejectOnQuotaInterfaces=" + rejectOnQuotaInterfaces);
+            }
+            mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+        } catch (IllegalStateException e) {
+            Slog.e(TAG, "IllegalStateException in setUidNetworkRules " + e);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote Exception in setUidNetworkRules " + e);
+        }
+    }
+
     /**
      * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
      * have at least a default mobile policy defined.
@@ -955,7 +993,7 @@
         mUidRules.put(uid, uidRules);
 
         final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
-        //kernelSetUidRejectPaid(uid, rejectPaid);
+        setUidNetworkRules(uid, rejectMetered);
 
         // dispatch changed rule to existing listeners
         mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();