diff options
| author | 2016-03-22 14:53:13 -0700 | |
|---|---|---|
| committer | 2016-03-25 12:33:47 -0700 | |
| commit | 65be3025fd07d53137f5434794d1d1b3a0933aab (patch) | |
| tree | 894e539a27506d88bb8e4644b27ffa97ba689116 | |
| parent | 4a2f9857c2759661a54d8705fb65e1ce500d1907 (diff) | |
Refactored NetworkManagerService to support Data Saver.
Netd provides 2 bandwidth control rules to restrict which uids can use
metered networks:
- bw_penalty_box is a blacklist-based firewall chain used to determine
which uids do not have access to metered interfaces.
- bw_happy_box is whitelist-based firewall chain used to determine which
uids have access to metered interfaces.
Currently, both NetworkManagerService (NMS) and
NetworkPolicyManagerService (NPMS) uses just the bw_penalty_box rule,
which makes turning Data Saver mode on / off too slow (since NPMS needs
to build the bw_penalty_box on demand); this CL adds support for both
rules on NMS, although NPMS doesn't take advantage of it yet (it will be
refactored in a separate CL).
BUG: 27127112
BUG: 26685616
Change-Id: Ib954574f7c86269fc9b4cf8ce4ba72ba5878c23d
4 files changed, 122 insertions, 47 deletions
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 100f6a165b1d..24a6cdf83b7a 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -293,7 +293,9 @@ interface INetworkManagementService /** * Control network activity of a UID over interfaces with a quota limit. */ - void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces); + void setUidMeteredNetworkBlacklist(int uid, boolean enable); + void setUidMeteredNetworkWhitelist(int uid, boolean enable); + boolean setDataSaverModeEnabled(boolean enable); void setUidCleartextNetworkPolicy(int uid, int policy); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 548b66284937..b8c5e63762e2 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -209,9 +209,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub /** Set of interfaces with active alerts. */ @GuardedBy("mQuotaLock") private HashMap<String, Long> mActiveAlerts = Maps.newHashMap(); - /** Set of UIDs with active reject rules. */ + /** Set of UIDs blacklisted on metered networks. */ @GuardedBy("mQuotaLock") - private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray(); + private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray(); + /** Set of UIDs whitelisted on metered networks. */ + @GuardedBy("mQuotaLock") + private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray(); /** Set of UIDs with cleartext penalties. */ @GuardedBy("mQuotaLock") private SparseIntArray mUidCleartextPolicy = new SparseIntArray(); @@ -240,6 +243,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub @GuardedBy("mQuotaLock") final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray(); + @GuardedBy("mQuotaLock") + private boolean mDataSaverMode; + private Object mIdleTimerLock = new Object(); /** Set of interfaces with active idle timers. */ private static class IdleTimerParams { @@ -561,6 +567,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub // push any existing quota or UID rules synchronized (mQuotaLock) { + + setDataSaverModeEnabled(mDataSaverMode); + int size = mActiveQuotas.size(); if (size > 0) { if (DBG) Slog.d(TAG, "Pushing " + size + " active quota rules"); @@ -581,13 +590,25 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } - size = mUidRejectOnQuota.size(); + size = mUidRejectOnMetered.size(); if (size > 0) { - if (DBG) Slog.d(TAG, "Pushing " + size + " active UID rules"); - final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota; - mUidRejectOnQuota = new SparseBooleanArray(); + if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered whitelist rules"); + final SparseBooleanArray uidRejectOnQuota = mUidRejectOnMetered; + mUidRejectOnMetered = new SparseBooleanArray(); for (int i = 0; i < uidRejectOnQuota.size(); i++) { - setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i)); + setUidMeteredNetworkBlacklist(uidRejectOnQuota.keyAt(i), + uidRejectOnQuota.valueAt(i)); + } + } + + size = mUidAllowOnMetered.size(); + if (size > 0) { + if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered blacklist rules"); + final SparseBooleanArray uidAcceptOnQuota = mUidAllowOnMetered; + mUidAllowOnMetered = new SparseBooleanArray(); + for (int i = 0; i < uidAcceptOnQuota.size(); i++) { + setUidMeteredNetworkWhitelist(uidAcceptOnQuota.keyAt(i), + uidAcceptOnQuota.valueAt(i)); } } @@ -738,6 +759,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks { @Override public void onDaemonConnected() { + Slog.i(TAG, "onDaemonConnected()"); // event is dispatched from internal NDC thread, so we prepare the // daemon back on main thread. if (mConnectedSignal != null) { @@ -1698,28 +1720,30 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } - @Override - public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { + private void setUidOnMeteredNetworkList(SparseBooleanArray quotaList, int uid, + boolean blacklist, boolean enable) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); // silently discard when control disabled // TODO: eventually migrate to be always enabled if (!mBandwidthControlEnabled) return; + final String chain = blacklist ? "naughtyapps" : "niceapps"; + final String suffix = enable ? "add" : "remove"; + synchronized (mQuotaLock) { - final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false); - if (oldRejectOnQuota == rejectOnQuotaInterfaces) { + final boolean oldEnable = quotaList.get(uid, false); + if (oldEnable == enable) { // TODO: eventually consider throwing return; } try { - mConnector.execute("bandwidth", - rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid); - if (rejectOnQuotaInterfaces) { - mUidRejectOnQuota.put(uid, true); + mConnector.execute("bandwidth", suffix + chain, uid); + if (enable) { + quotaList.put(uid, true); } else { - mUidRejectOnQuota.delete(uid); + quotaList.delete(uid); } } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); @@ -1728,6 +1752,39 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override + public void setUidMeteredNetworkBlacklist(int uid, boolean enable) { + setUidOnMeteredNetworkList(mUidRejectOnMetered, uid, true, enable); + } + + @Override + public void setUidMeteredNetworkWhitelist(int uid, boolean enable) { + setUidOnMeteredNetworkList(mUidAllowOnMetered, uid, false, enable); + } + + @Override + public boolean setDataSaverModeEnabled(boolean enable) { + if (DBG) Log.d(TAG, "setDataSaverMode: " + enable); + synchronized (mQuotaLock) { + if (mDataSaverMode == enable) { + Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode); + return true; + } + try { + final boolean changed = mNetdService.bandwidthEnableDataSaver(enable); + if (changed) { + mDataSaverMode = enable; + } else { + Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed"); + } + return changed; + } catch (RemoteException e) { + Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e); + return false; + } + } + } + + @Override public void setUidCleartextNetworkPolicy(int uid, int policy) { if (Binder.getCallingUid() != uid) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); @@ -2221,29 +2278,22 @@ public class NetworkManagementService extends INetworkManagementService.Stub synchronized (mQuotaLock) { pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString()); pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString()); - } - - synchronized (mUidRejectOnQuota) { - pw.print("UID reject on quota ifaces: ["); - final int size = mUidRejectOnQuota.size(); - for (int i = 0; i < size; i++) { - pw.print(mUidRejectOnQuota.keyAt(i)); - if (i < size - 1) pw.print(","); - } - pw.println("]"); + pw.print("Data saver mode: "); pw.println(mDataSaverMode); + dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered); + dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered); } synchronized (mUidFirewallRules) { dumpUidFirewallRule(pw, "", mUidFirewallRules); } - pw.println("UID firewall standby chain enabled: " + + pw.print("UID firewall standby chain enabled: "); pw.println( mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)); synchronized (mUidFirewallStandbyRules) { dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules); } - pw.println("UID firewall dozable chain enabled: " + + pw.print("UID firewall dozable chain enabled: "); pw.println( mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)); synchronized (mUidFirewallDozableRules) { dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules); @@ -2267,6 +2317,29 @@ public class NetworkManagementService extends INetworkManagementService.Stub } pw.print("Firewall enabled: "); pw.println(mFirewallEnabled); + pw.print("Netd service status: " ); + if (mNetdService == null) { + pw.println("disconnected"); + } else { + try { + final boolean alive = mNetdService.isAlive(); + pw.println(alive ? "alive": "dead"); + } catch (RemoteException e) { + pw.println("unreachable"); + } + } + } + + private void dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list) { + pw.print("UID bandwith control "); + pw.print(name); + pw.print(" rule: ["); + final int size = list.size(); + for (int i = 0; i < size; i++) { + pw.print(list.keyAt(i)); + if (i < size - 1) pw.print(","); + } + pw.println("]"); } private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 49ae2936d6ff..9b92e4f0f04d 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -2803,7 +2803,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { try { - mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces); + mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces); } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting uid rules", e); } catch (RemoteException e) { diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 72a458bdb96c..622e46efdf2c 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -313,7 +313,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { public void testScreenChangesRules() throws Exception { Future<Void> future; - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, true); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -322,7 +322,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // push strict policy for foreground uid, verify ALLOW rule - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, true); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -332,7 +332,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // now turn screen off and verify REJECT rule expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce(); - expectSetUidNetworkRules(UID_A, true); + expectSetUidMeteredNetworkBlacklist(UID_A, true); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_REJECT_METERED); replay(); @@ -342,7 +342,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // and turn screen back on, verify ALLOW rule restored expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce(); - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, true); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -354,7 +354,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { public void testPolicyNone() throws Exception { Future<Void> future; - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, true); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -363,7 +363,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // POLICY_NONE should RULE_ALLOW in foreground - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, true); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -372,7 +372,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // POLICY_NONE should RULE_ALLOW in background - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -385,7 +385,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { Future<Void> future; // POLICY_REJECT should RULE_ALLOW in background - expectSetUidNetworkRules(UID_A, true); + expectSetUidMeteredNetworkBlacklist(UID_A, true); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_REJECT_METERED); replay(); @@ -394,7 +394,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // POLICY_REJECT should RULE_ALLOW in foreground - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, true); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -403,7 +403,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // POLICY_REJECT should RULE_REJECT in background - expectSetUidNetworkRules(UID_A, true); + expectSetUidMeteredNetworkBlacklist(UID_A, true); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_REJECT_METERED); replay(); @@ -416,7 +416,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { Future<Void> future; // POLICY_NONE should have RULE_ALLOW in background - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -426,7 +426,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // adding POLICY_REJECT should cause RULE_REJECT - expectSetUidNetworkRules(UID_A, true); + expectSetUidMeteredNetworkBlacklist(UID_A, true); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_REJECT_METERED); replay(); @@ -435,7 +435,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // removing POLICY_REJECT should return us to RULE_ALLOW - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -632,7 +632,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { Future<Void> future; // POLICY_REJECT should RULE_REJECT in background - expectSetUidNetworkRules(UID_A, true); + expectSetUidMeteredNetworkBlacklist(UID_A, true); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_REJECT_METERED); replay(); @@ -641,7 +641,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { verifyAndReset(); // uninstall should clear RULE_REJECT - expectSetUidNetworkRules(UID_A, false); + expectSetUidMeteredNetworkBlacklist(UID_A, false); expectSetUidForeground(UID_A, false); future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); replay(); @@ -890,9 +890,9 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { expectLastCall().atLeastOnce(); } - private void expectSetUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) + private void expectSetUidMeteredNetworkBlacklist(int uid, boolean rejectOnQuotaInterfaces) throws Exception { - mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces); + mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces); expectLastCall().atLeastOnce(); } |