Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 771d0c2b authored by Felipe Leme's avatar Felipe Leme Committed by Android (Google) Code Review
Browse files

Merge "Refactored NetworkManagerService to support Data Saver." into nyc-dev

parents fb2d2cec 65be3025
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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);

+101 −28
Original line number Diff line number Diff line
@@ -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 {
@@ -583,6 +589,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");
@@ -603,13 +612,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));
                }
            }

@@ -723,6 +744,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) {
@@ -1683,28 +1705,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();
@@ -1712,6 +1736,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) {
@@ -2206,29 +2263,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);
@@ -2252,6 +2302,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) {
+1 −1
Original line number Diff line number Diff line
@@ -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) {
+17 −17
Original line number Diff line number Diff line
@@ -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();
    }