Merge "system_server: add two child chains to firewall" into mnc-dev

This commit is contained in:
Xiaohui Chen
2015-06-17 23:50:23 +00:00
committed by Android (Google) Code Review
5 changed files with 285 additions and 29 deletions

View File

@@ -61,6 +61,17 @@ public class NetworkPolicyManager {
public static final int FIREWALL_RULE_ALLOW = 1;
public static final int FIREWALL_RULE_DENY = 2;
public static final int FIREWALL_TYPE_WHITELIST = 0;
public static final int FIREWALL_TYPE_BLACKLIST = 1;
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 String FIREWALL_CHAIN_NAME_NONE = "none";
public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable";
public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
/**

View File

@@ -342,7 +342,9 @@ interface INetworkManagementService
void setFirewallInterfaceRule(String iface, boolean allow);
void setFirewallEgressSourceRule(String addr, boolean allow);
void setFirewallEgressDestRule(String addr, int port, boolean allow);
void setFirewallUidRule(int uid, int rule);
void setFirewallUidRule(int chain, int uid, int rule);
void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
void setFirewallChainEnabled(int chain, boolean enable);
/**
* Set all packets from users in ranges to go through VPN specified by netId.

View File

@@ -19,6 +19,15 @@ package com.android.server;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
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_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
@@ -35,6 +44,7 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.Tethe
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;
import android.net.ConnectivityManager;
@@ -192,6 +202,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub
/** Set of UIDs that are to be blocked/allowed by firewall controller. */
@GuardedBy("mQuotaLock")
private SparseIntArray mUidFirewallRules = new SparseIntArray();
/**
* Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
* to application idles.
*/
@GuardedBy("mQuotaLock")
private SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
/**
* Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
* to device idles.
*/
@GuardedBy("mQuotaLock")
private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
private boolean mStandbyChainEnabled = false;
private boolean mDozableChainEnabled = false;
private Object mIdleTimerLock = new Object();
/** Set of interfaces with active idle timers. */
@@ -282,6 +307,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
public void systemReady() {
// init firewall states
mDozableChainEnabled = false;
mStandbyChainEnabled = true;
prepareNativeDaemon();
if (DBG) Slog.d(TAG, "Prepared");
}
@@ -568,9 +596,38 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final SparseIntArray uidFirewallRules = mUidFirewallRules;
mUidFirewallRules = new SparseIntArray();
for (int i = 0; i < uidFirewallRules.size(); i++) {
setFirewallUidRule(uidFirewallRules.keyAt(i), uidFirewallRules.valueAt(i));
setFirewallUidRuleInternal(FIREWALL_CHAIN_NONE, uidFirewallRules.keyAt(i),
uidFirewallRules.valueAt(i));
}
}
size = mUidFirewallStandbyRules.size();
if (size > 0) {
Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules");
final SparseIntArray uidFirewallRules = mUidFirewallStandbyRules;
mUidFirewallStandbyRules = new SparseIntArray();
for (int i = 0; i < uidFirewallRules.size(); i++) {
setFirewallUidRuleInternal(FIREWALL_CHAIN_STANDBY, uidFirewallRules.keyAt(i),
uidFirewallRules.valueAt(i));
}
}
if (mStandbyChainEnabled) {
setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
}
size = mUidFirewallDozableRules.size();
if (size > 0) {
Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules");
final SparseIntArray uidFirewallRules = mUidFirewallDozableRules;
mUidFirewallDozableRules = new SparseIntArray();
for (int i = 0; i < uidFirewallRules.size(); i++) {
setFirewallUidRuleInternal(FIREWALL_CHAIN_DOZABLE, uidFirewallRules.keyAt(i),
uidFirewallRules.valueAt(i));
}
}
if (mDozableChainEnabled) {
setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
}
}
}
@@ -1954,13 +2011,78 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
@Override
public void setFirewallUidRule(int uid, int rule) {
public void setFirewallChainEnabled(int chain, boolean enable) {
enforceSystemUid();
if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
Preconditions.checkState(mFirewallEnabled);
final String operation = enable ? "enable_chain" : "disable_chain";
try {
String chainName;
switch(chain) {
case FIREWALL_CHAIN_STANDBY:
chainName = FIREWALL_CHAIN_NAME_STANDBY;
mStandbyChainEnabled = enable;
break;
case FIREWALL_CHAIN_DOZABLE:
chainName = FIREWALL_CHAIN_NAME_DOZABLE;
mDozableChainEnabled = enable;
break;
default:
throw new IllegalArgumentException("Bad child chain: " + chain);
}
mConnector.execute("firewall", operation, chainName);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
private int getFirewallType(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
return FIREWALL_TYPE_BLACKLIST;
case FIREWALL_CHAIN_DOZABLE:
return FIREWALL_TYPE_WHITELIST;
default:
return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
}
}
@Override
public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
enforceSystemUid();
SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
SparseIntArray newRules = new SparseIntArray();
// apply new set of rules
for (int index = uids.length - 1; index >= 0; --index) {
int uid = uids[index];
int rule = rules[index];
setFirewallUidRule(chain, uid, rule);
newRules.put(uid, rule);
}
// collect the rules to remove.
SparseIntArray rulesToRemove = new SparseIntArray();
for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
int uid = uidFirewallRules.keyAt(index);
if (newRules.indexOfKey(uid) < 0) {
rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
}
}
// remove dead rules
for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
int uid = rulesToRemove.keyAt(index);
setFirewallUidRuleInternal(chain, uid, FIREWALL_RULE_DEFAULT);
}
}
@Override
public void setFirewallUidRule(int chain, int uid, int rule) {
enforceSystemUid();
setFirewallUidRuleInternal(chain, uid, rule);
}
private void setFirewallUidRuleInternal(int chain, int uid, int rule) {
synchronized (mQuotaLock) {
final int oldUidFirewallRule = mUidFirewallRules.get(uid);
SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
if (DBG) {
Slog.d(TAG, "oldRule = " + oldUidFirewallRule
+ ", newRule=" + rule + " for uid=" + uid);
@@ -1973,7 +2095,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
try {
String ruleName;
if (isFirewallEnabled()) { // Whitelist mode
if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
ruleName = "allow";
} else {
@@ -1988,17 +2110,44 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
mUidFirewallRules.delete(uid);
uidFirewallRules.delete(uid);
} else {
mUidFirewallRules.put(uid, rule);
uidFirewallRules.put(uid, rule);
}
mConnector.execute("firewall", "set_uid_rule", uid, ruleName);
mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
ruleName);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
}
private @NonNull SparseIntArray getUidFirewallRules(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
return mUidFirewallStandbyRules;
case FIREWALL_CHAIN_DOZABLE:
return mUidFirewallDozableRules;
case FIREWALL_CHAIN_NONE:
return mUidFirewallRules;
default:
throw new IllegalArgumentException("Unknown chain:" + chain);
}
}
public @NonNull String getFirewallChainName(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
return FIREWALL_CHAIN_NAME_STANDBY;
case FIREWALL_CHAIN_DOZABLE:
return FIREWALL_CHAIN_NAME_DOZABLE;
case FIREWALL_CHAIN_NONE:
return FIREWALL_CHAIN_NAME_NONE;
default:
throw new IllegalArgumentException("Unknown chain:" + chain);
}
}
private static void enforceSystemUid() {
final int uid = Binder.getCallingUid();
if (uid != Process.SYSTEM_UID) {
@@ -2123,6 +2272,32 @@ public class NetworkManagementService extends INetworkManagementService.Stub
pw.println("]");
}
pw.println("UID firewall standby chain enabled: " + mStandbyChainEnabled);
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("]");
}
pw.println("UID firewall dozable chain enabled: " + mDozableChainEnabled);
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(",");
}
pw.println("]");
}
synchronized (mIdleTimerLock) {
pw.println("Idle timers:");
for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {

View File

@@ -17,6 +17,7 @@
package com.android.server.net;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
@@ -201,8 +202,8 @@ public class LockdownVpnTracker {
setFirewallEgressSourceRule(addr, true);
}
mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_ALLOW);
mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_ALLOW);
mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_ALLOW);
mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, Os.getuid(), FIREWALL_RULE_ALLOW);
mErrorCount = 0;
mAcceptedIface = iface;
@@ -291,8 +292,8 @@ public class LockdownVpnTracker {
setFirewallEgressSourceRule(addr, false);
}
mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_DEFAULT);
mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_DEFAULT);
mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_DEFAULT);
mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE,Os.getuid(), FIREWALL_RULE_DEFAULT);
mAcceptedSourceAddr = null;
}

View File

@@ -36,8 +36,10 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED;
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_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -80,7 +82,6 @@ import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.IProcessObserver;
import android.app.IUidObserver;
import android.app.Notification;
import android.app.PendingIntent;
@@ -141,7 +142,6 @@ import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TrustedTime;
@@ -279,6 +279,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
final SparseIntArray mUidRules = new SparseIntArray();
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
/**
* UIDs that have been white-listed to always be able to have network access
@@ -412,8 +413,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
final PackageManager pm = mContext.getPackageManager();
synchronized (mRulesLock) {
updatePowerSaveWhitelistLocked();
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -1103,7 +1102,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
// will not have a bandwidth limit. Also only do this if restrict
// background data use is *not* enabled, since that takes precendence
// use over those networks can have a cost associated with it).
final boolean powerSave = (mRestrictPower || mDeviceIdleMode) && !mRestrictBackground;
final boolean powerSave = mRestrictPower && !mRestrictBackground;
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
@@ -2024,6 +2023,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
}
}
void updateRulesForDeviceIdleLocked() {
if (mDeviceIdleMode) {
// sync the whitelists before enable dozable chain. We don't care about the rules if
// we are disabling the chain.
SparseIntArray uidRules = new SparseIntArray();
final List<UserInfo> users = mUserManager.getUsers();
for (UserInfo user : users) {
for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
int uid = UserHandle.getUid(user.id, appId);
uidRules.put(uid, FIREWALL_RULE_ALLOW);
}
for (int i = mPowerSaveWhitelistAppIds.size() - 1; i >= 0; i--) {
int appId = mPowerSaveWhitelistAppIds.keyAt(i);
int uid = UserHandle.getUid(user.id, appId);
uidRules.put(uid, FIREWALL_RULE_ALLOW);
}
}
setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
}
enableFirewallChain(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
}
/**
* Update rules that might be changed by {@link #mRestrictBackground},
* {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
@@ -2034,10 +2056,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
// If we are in restrict power mode, we allow all important apps
// to have data access. Otherwise, we restrict data access to only
// the top apps.
mCurForegroundState = (!mRestrictBackground && (mRestrictPower || mDeviceIdleMode))
mCurForegroundState = (!mRestrictBackground && mRestrictPower)
? ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
: ActivityManager.PROCESS_STATE_TOP;
updateRulesForDeviceIdleLocked();
// update rules for all installed applications
final List<UserInfo> users = mUserManager.getUsers();
final List<ApplicationInfo> apps = pm.getInstalledApplications(
@@ -2131,7 +2155,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
// uid in background, and global background disabled
uidRules = RULE_REJECT_METERED;
}
} else if (mRestrictPower || mDeviceIdleMode) {
} else if (mRestrictPower) {
final boolean whitelisted = mPowerSaveWhitelistAppIds.get(appId)
|| mPowerSaveTempWhitelistAppIds.get(appId);
if (!whitelisted && !uidForeground
@@ -2162,7 +2186,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
final boolean oldFirewallReject = (oldRules & RULE_REJECT_ALL) != 0;
final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0;
if (oldFirewallReject != firewallReject) {
setUidFirewallRules(uid, firewallReject);
setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject);
if (mDeviceIdleMode && !firewallReject) {
// if we are in device idle mode, and we decide to allow this uid. we need to punch
// a hole in the device idle chain.
setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, false);
}
}
// dispatch changed rule to existing listeners
@@ -2314,14 +2343,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
}
/**
* Add or remove a uid to the firewall blacklist for all network ifaces.
* @param uid
* @param rejectOnAll
* Set uid rules on a particular firewall chain. This is going to synchronize the rules given
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
private void setUidFirewallRules(int uid, boolean rejectOnAll) {
private void setUidFirewallRules(int chain, SparseIntArray uidRules) {
try {
mNetworkManager.setFirewallUidRule(uid,
rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_DEFAULT);
int size = uidRules.size();
int[] uids = new int[size];
int[] rules = new int[size];
for(int index = size - 1; index >= 0; --index) {
uids[index] = uidRules.keyAt(index);
rules[index] = uidRules.valueAt(index);
}
mNetworkManager.setFirewallUidRules(chain, uids, rules);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -2329,6 +2364,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
}
}
/**
* Add or remove a uid to the firewall blacklist for all network ifaces.
*/
private void setUidFirewallRule(int chain, int uid, boolean rejectOnAll) {
try {
mNetworkManager.setFirewallUidRule(chain, uid,
rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
}
/**
* Add or remove a uid to the firewall blacklist for all network ifaces.
*/
private void enableFirewallChain(int chain, boolean enable) {
if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
mFirewallChainStates.get(chain) == enable) {
// All is the same, nothing to do.
return;
}
try {
mNetworkManager.setFirewallChainEnabled(chain, enable);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem enable firewall chain", e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
}
private long getTotalBytes(NetworkTemplate template, long start, long end) {
try {
return mNetworkStats.getNetworkTotalBytes(template, start, end);