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

Commit 011b98f9 authored by Felipe Leme's avatar Felipe Leme
Browse files

Created a firewall chain for power save mode.

When power-save mode was first implemented, there were no firewall rules
on netd, so the solution was to make all network interface metered and
re-use the bw_penalty_box chain.

This change removes that workaround by creating a explicit fw_powersave
chain, whose behavior is similar to fw_dozable (in fact, it reuses some
of its code); such change not only makes network restrictions on
power-save mode simpler, but it also allows to optimze how the restrict
network rules are changed (which will be done in a separate change).

BUG: 27127112
BUG: 26685616
Change-Id: I7f7a7b1c1855e916c6651ad90da29fe187a7bea2
parent 2cca0a93
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -68,10 +68,12 @@ public class NetworkPolicyManager {
    public static final int FIREWALL_CHAIN_NONE = 0;
    public static final int FIREWALL_CHAIN_DOZABLE = 1;
    public static final int FIREWALL_CHAIN_STANDBY = 2;
    public static final int FIREWALL_CHAIN_POWERSAVE = 3;

    public static final String FIREWALL_CHAIN_NAME_NONE = "none";
    public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable";
    public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
    public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave";

    private static final boolean ALLOW_PLATFORM_APP_POLICY = true;

+54 −28
Original line number Diff line number Diff line
@@ -22,8 +22,10 @@ import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
@@ -43,7 +45,6 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.Tethe
import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;

import android.annotation.NonNull;
import android.app.ActivityManagerNative;
import android.content.Context;
@@ -226,6 +227,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     */
    @GuardedBy("mQuotaLock")
    private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
    /**
     * Set of UIDs that are to be blocked/allowed by firewall controller.  This set of Ids matches
     * to device on power-save mode.
     */
    @GuardedBy("mQuotaLock")
    private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
    /** Set of states for the child firewall chains. True if the chain is active. */
    @GuardedBy("mQuotaLock")
    final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -621,6 +628,20 @@ public class NetworkManagementService extends INetworkManagementService.Stub
            if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
                setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
            }

            size = mUidFirewallPowerSaveRules.size();
            if (size > 0) {
                Slog.d(TAG, "Pushing " + size + " active firewall powersave UID rules");
                final SparseIntArray uidFirewallRules = mUidFirewallPowerSaveRules;
                mUidFirewallPowerSaveRules = new SparseIntArray();
                for (int i = 0; i < uidFirewallRules.size(); i++) {
                    setFirewallUidRuleInternal(FIREWALL_CHAIN_POWERSAVE, uidFirewallRules.keyAt(i),
                            uidFirewallRules.valueAt(i));
                }
            }
            if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)) {
                setFirewallChainEnabled(FIREWALL_CHAIN_POWERSAVE, true);
            }
        }
    }

@@ -2023,6 +2044,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                    case FIREWALL_CHAIN_DOZABLE:
                        chainName = FIREWALL_CHAIN_NAME_DOZABLE;
                        break;
                    case FIREWALL_CHAIN_POWERSAVE:
                        chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
                        break;
                    default:
                        throw new IllegalArgumentException("Bad child chain: " + chain);
                }
@@ -2039,6 +2063,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                return FIREWALL_TYPE_BLACKLIST;
            case FIREWALL_CHAIN_DOZABLE:
                return FIREWALL_TYPE_WHITELIST;
            case FIREWALL_CHAIN_POWERSAVE:
                return FIREWALL_TYPE_WHITELIST;
            default:
                return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
        }
@@ -2138,6 +2164,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                return mUidFirewallStandbyRules;
            case FIREWALL_CHAIN_DOZABLE:
                return mUidFirewallDozableRules;
            case FIREWALL_CHAIN_POWERSAVE:
                return mUidFirewallPowerSaveRules;
            case FIREWALL_CHAIN_NONE:
                return mUidFirewallRules;
            default:
@@ -2151,6 +2179,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                return FIREWALL_CHAIN_NAME_STANDBY;
            case FIREWALL_CHAIN_DOZABLE:
                return FIREWALL_CHAIN_NAME_DOZABLE;
            case FIREWALL_CHAIN_POWERSAVE:
                return FIREWALL_CHAIN_NAME_POWERSAVE;
            case FIREWALL_CHAIN_NONE:
                return FIREWALL_CHAIN_NAME_NONE;
            default:
@@ -2271,43 +2301,25 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        }

        synchronized (mUidFirewallRules) {
            pw.print("UID firewall rule: [");
            final int size = mUidFirewallRules.size();
            for (int i = 0; i < size; i++) {
                pw.print(mUidFirewallRules.keyAt(i));
                pw.print(":");
                pw.print(mUidFirewallRules.valueAt(i));
                if (i < size - 1) pw.print(",");
            }
            pw.println("]");
            dumpUidFirewallRule(pw, "", mUidFirewallRules);
        }

        pw.println("UID firewall standby chain enabled: " +
                mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
        synchronized (mUidFirewallStandbyRules) {
            pw.print("UID firewall standby rule: [");
            final int size = mUidFirewallStandbyRules.size();
            for (int i = 0; i < size; i++) {
                pw.print(mUidFirewallStandbyRules.keyAt(i));
                pw.print(":");
                pw.print(mUidFirewallStandbyRules.valueAt(i));
                if (i < size - 1) pw.print(",");
            }
            pw.println("]");
            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
        }

        pw.println("UID firewall dozable chain enabled: " +
                mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
        synchronized (mUidFirewallDozableRules) {
            pw.print("UID firewall dozable rule: [");
            final int size = mUidFirewallDozableRules.size();
            for (int i = 0; i < size; i++) {
                pw.print(mUidFirewallDozableRules.keyAt(i));
                pw.print(":");
                pw.print(mUidFirewallDozableRules.valueAt(i));
                if (i < size - 1) pw.print(",");
            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
        }
            pw.println("]");

        pw.println("UID firewall powersave chain enabled: " +
                mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE));
        synchronized (mUidFirewallPowerSaveRules) {
            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
        }

        synchronized (mIdleTimerLock) {
@@ -2324,6 +2336,20 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
    }

    private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
        pw.print("UID firewall");
        pw.print(name);
        pw.print(" rule: [");
        final int size = rules.size();
        for (int i = 0; i < size; i++) {
            pw.print(rules.keyAt(i));
            pw.print(":");
            pw.print(rules.valueAt(i));
            if (i < size - 1) pw.print(",");
        }
        pw.println("]");
    }

    @Override
    public void createPhysicalNetwork(int netId, String permission) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+60 −31
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
@@ -294,6 +295,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
    final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
    final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();

    /** Set of states for the child firewall chains. True if the chain is active. */
    final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -522,9 +524,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    new PowerManagerInternal.LowPowerModeListener() {
                @Override
                public void onLowPowerModeChanged(boolean enabled) {
                    if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
                    synchronized (mRulesLock) {
                        if (mRestrictPower != enabled) {
                            mRestrictPower = enabled;
                            updateRulesForRestrictPowerLocked();
                            updateRulesForGlobalChangeLocked(true);
                        }
                    }
@@ -1175,13 +1179,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            return;
        }

        // If we are in restrict power mode, we want to treat all interfaces
        // as metered, to restrict access to the network by uid.  However, we
        // will not have a bandwidth limit.  Also only do this if restrict
        // background data use is *not* enabled, since that takes precedence
        // use over those networks can have a cost associated with it).
        final boolean powerSave = mRestrictPower && !mRestrictBackground;

        // First, generate identities of all connected networks so we can
        // quickly compare them against all defined policies below.
        final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
@@ -1193,9 +1190,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                final String baseIface = state.linkProperties.getInterfaceName();
                if (baseIface != null) {
                    connIdents.add(Pair.create(baseIface, ident));
                    if (powerSave) {
                        connIfaces.add(baseIface);
                    }
                }

                // Stacked interfaces are considered to have same identity as
@@ -1205,9 +1199,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    final String stackedIface = stackedLink.getInterfaceName();
                    if (stackedIface != null) {
                        connIdents.add(Pair.create(stackedIface, ident));
                        if (powerSave) {
                            connIfaces.add(stackedIface);
                        }
                    }
                }
            }
@@ -1286,9 +1277,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    removeInterfaceQuota(iface);
                    setInterfaceQuota(iface, quotaBytes);
                    newMeteredIfaces.add(iface);
                    if (powerSave) {
                        connIfaces.remove(iface);
                    }
                }
            }

@@ -2299,10 +2287,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            // state changed, push updated rules
            mUidState.put(uid, uidState);
            updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
            if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
                    != isProcStateAllowedWhileIdle(uidState)) {
            if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
                    != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
                if (mDeviceIdleMode) {
                    updateRuleForDeviceIdleLocked(uid);
                }
                if (mRestrictPower) {
                    updateRulesForRestrictPowerLocked(uid);
                }
            }
        }
    }

@@ -2317,6 +2310,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                if (mDeviceIdleMode) {
                    updateRuleForDeviceIdleLocked(uid);
                }
                if (mRestrictPower) {
                    updateRulesForRestrictPowerLocked(uid);
                }
            }
        }
    }
@@ -2354,15 +2350,36 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    static boolean isProcStateAllowedWhileIdle(int procState) {
    static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
        return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
    }

    void updateRulesForRestrictPowerLocked() {
        updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
                mUidFirewallPowerSaveRules);
    }

    void updateRulesForRestrictPowerLocked(int uid) {
        updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
    }

    void updateRulesForDeviceIdleLocked() {
        if (mDeviceIdleMode) {
            // sync the whitelists before enable dozable chain.  We don't care about the rules if
        updateRulesForWhitelistedPowerSaveLocked(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
                mUidFirewallDozableRules);
    }

    void updateRuleForDeviceIdleLocked(int uid) {
        updateRulesForWhitelistedPowerSaveLocked(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
    }

    // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
    // for whitelisting, we can reuse their logic in this method.
    private void updateRulesForWhitelistedPowerSaveLocked(boolean enabled, int chain,
            SparseIntArray rules) {
        if (enabled) {
            // Sync the whitelists before enabling the chain.  We don't care about the rules if
            // we are disabling the chain.
            final SparseIntArray uidRules = mUidFirewallDozableRules;
            final SparseIntArray uidRules = rules;
            uidRules.clear();
            final List<UserInfo> users = mUserManager.getUsers();
            for (int ui = users.size() - 1; ui >= 0; ui--) {
@@ -2381,24 +2398,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                }
            }
            for (int i = mUidState.size() - 1; i >= 0; i--) {
                if (isProcStateAllowedWhileIdle(mUidState.valueAt(i))) {
                if (isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.valueAt(i))) {
                    uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
                }
            }
            setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
            setUidFirewallRules(chain, uidRules);
        }

        enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
        enableFirewallChainLocked(chain, enabled);
    }

    void updateRuleForDeviceIdleLocked(int uid) {
        if (mDeviceIdleMode) {
    // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
    // for whitelisting, we can reuse their logic in this method.
    private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) {
        if (enabled) {
            int appId = UserHandle.getAppId(uid);
            if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId)
                    || isProcStateAllowedWhileIdle(mUidState.get(uid))) {
                setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_ALLOW);
                    || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
                setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
            } else {
                setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
                setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
            }
        }

@@ -2458,6 +2477,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

        updateRulesForDeviceIdleLocked();
        updateRulesForAppIdleLocked();
        updateRulesForRestrictPowerLocked();

        // update rules for all installed applications
        final List<UserInfo> users = mUserManager.getUsers();
@@ -2491,6 +2511,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                int uid = UserHandle.getUid(user.id, appId);
                updateRuleForAppIdleLocked(uid);
                updateRuleForDeviceIdleLocked(uid);
                updateRulesForRestrictPowerLocked(uid);
            }
        }
    }
@@ -2583,6 +2604,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            uidRules = RULE_REJECT_ALL;
        }

        // Check powersave state, which is whitelist
        if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)
                && mUidFirewallPowerSaveRules.get(uid, FIREWALL_RULE_DEFAULT) != FIREWALL_RULE_ALLOW) {
            uidRules = RULE_REJECT_ALL;
        }

        // Check standby state, which is blacklist
        if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)
                && mUidFirewallStandbyRules.get(uid, FIREWALL_RULE_DEFAULT) == FIREWALL_RULE_DENY) {
@@ -2810,6 +2837,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            mUidFirewallDozableRules.put(uid, rule);
        } else if (chain == FIREWALL_CHAIN_STANDBY) {
            mUidFirewallStandbyRules.put(uid, rule);
        } else if (chain == FIREWALL_CHAIN_POWERSAVE) {
            mUidFirewallPowerSaveRules.put(uid, rule);
        }

        try {