Merge changes Ifc3708c1,If07045c1

* changes:
  Remove uid rules computation in NPMS.
  Include blocked reasons in the netpolicy dump.
This commit is contained in:
Sudheer Shanka
2021-11-25 04:28:56 +00:00
committed by Gerrit Code Review
2 changed files with 361 additions and 395 deletions

View File

@@ -39,6 +39,7 @@ import android.util.Slog;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.RingBuffer; import com.android.internal.util.RingBuffer;
import com.android.server.am.ProcessList; import com.android.server.am.ProcessList;
import com.android.server.net.NetworkPolicyManagerService.UidBlockedState;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
@@ -72,16 +73,6 @@ public class NetworkPolicyLogger {
private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13; private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13;
private static final int EVENT_APP_IDLE_WL_CHANGED = 14; private static final int EVENT_APP_IDLE_WL_CHANGED = 14;
static final int NTWK_BLOCKED_POWER = 0;
static final int NTWK_ALLOWED_NON_METERED = 1;
static final int NTWK_BLOCKED_DENYLIST = 2;
static final int NTWK_ALLOWED_ALLOWLIST = 3;
static final int NTWK_ALLOWED_TMP_ALLOWLIST = 4;
static final int NTWK_BLOCKED_BG_RESTRICT = 5;
static final int NTWK_ALLOWED_DEFAULT = 6;
static final int NTWK_ALLOWED_SYSTEM = 7;
static final int NTWK_BLOCKED_RESTRICTED_MODE = 8;
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE); private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE); private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
private final LogBuffer mEventsBuffer = new LogBuffer(MAX_LOG_SIZE); private final LogBuffer mEventsBuffer = new LogBuffer(MAX_LOG_SIZE);
@@ -90,12 +81,13 @@ public class NetworkPolicyLogger {
private final Object mLock = new Object(); private final Object mLock = new Object();
void networkBlocked(int uid, int reason) { void networkBlocked(int uid, UidBlockedState uidBlockedState) {
synchronized (mLock) { synchronized (mLock) {
if (LOGD || uid == mDebugUid) { if (LOGD || uid == mDebugUid) {
Slog.d(TAG, uid + " is " + getBlockedReason(reason)); Slog.d(TAG, "Blocked state of uid: " + uidBlockedState.toString());
} }
mNetworkBlockedBuffer.networkBlocked(uid, reason); mNetworkBlockedBuffer.networkBlocked(uid, uidBlockedState.blockedReasons,
uidBlockedState.allowedReasons, uidBlockedState.effectiveBlockedReasons);
} }
} }
@@ -269,29 +261,6 @@ public class NetworkPolicyLogger {
} }
} }
private static String getBlockedReason(int reason) {
switch (reason) {
case NTWK_BLOCKED_POWER:
return "blocked by power restrictions";
case NTWK_ALLOWED_NON_METERED:
return "allowed on unmetered network";
case NTWK_BLOCKED_DENYLIST:
return "denylisted on metered network";
case NTWK_ALLOWED_ALLOWLIST:
return "allowlisted on metered network";
case NTWK_ALLOWED_TMP_ALLOWLIST:
return "temporary allowlisted on metered network";
case NTWK_BLOCKED_BG_RESTRICT:
return "blocked when background is restricted";
case NTWK_ALLOWED_DEFAULT:
return "allowed by default";
case NTWK_BLOCKED_RESTRICTED_MODE:
return "blocked by restricted networking mode";
default:
return String.valueOf(reason);
}
}
private static String getPolicyChangedLog(int uid, int oldPolicy, int newPolicy) { private static String getPolicyChangedLog(int uid, int oldPolicy, int newPolicy) {
return "Policy for " + uid + " changed from " return "Policy for " + uid + " changed from "
+ NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to " + NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to "
@@ -402,14 +371,17 @@ public class NetworkPolicyLogger {
data.timeStamp = System.currentTimeMillis(); data.timeStamp = System.currentTimeMillis();
} }
public void networkBlocked(int uid, int reason) { public void networkBlocked(int uid, int blockedReasons, int allowedReasons,
int effectiveBlockedReasons) {
final Data data = getNextSlot(); final Data data = getNextSlot();
if (data == null) return; if (data == null) return;
data.reset(); data.reset();
data.type = EVENT_NETWORK_BLOCKED; data.type = EVENT_NETWORK_BLOCKED;
data.ifield1 = uid; data.ifield1 = uid;
data.ifield2 = reason; data.ifield2 = blockedReasons;
data.ifield3 = allowedReasons;
data.ifield4 = effectiveBlockedReasons;
data.timeStamp = System.currentTimeMillis(); data.timeStamp = System.currentTimeMillis();
} }
@@ -554,7 +526,8 @@ public class NetworkPolicyLogger {
case EVENT_TYPE_GENERIC: case EVENT_TYPE_GENERIC:
return data.sfield1; return data.sfield1;
case EVENT_NETWORK_BLOCKED: case EVENT_NETWORK_BLOCKED:
return data.ifield1 + "-" + getBlockedReason(data.ifield2); return data.ifield1 + "-" + UidBlockedState.toString(
data.ifield2, data.ifield3, data.ifield4);
case EVENT_UID_STATE_CHANGED: case EVENT_UID_STATE_CHANGED:
return data.ifield1 + ":" + ProcessList.makeProcStateString(data.ifield2) return data.ifield1 + ":" + ProcessList.makeProcStateString(data.ifield2)
+ ":" + ActivityManager.getCapabilitiesSummary(data.ifield3) + ":" + ActivityManager.getCapabilitiesSummary(data.ifield3)
@@ -593,17 +566,18 @@ public class NetworkPolicyLogger {
} }
} }
public final static class Data { private static final class Data {
int type; public int type;
long timeStamp; public long timeStamp;
int ifield1; public int ifield1;
int ifield2; public int ifield2;
int ifield3; public int ifield3;
long lfield1; public int ifield4;
boolean bfield1; public long lfield1;
boolean bfield2; public boolean bfield1;
String sfield1; public boolean bfield2;
public String sfield1;
public void reset(){ public void reset(){
sfield1 = null; sfield1 = null;

View File

@@ -79,14 +79,10 @@ import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PE
import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM; import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
import static android.net.NetworkPolicyManager.MASK_RESTRICTED_MODE_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -135,15 +131,6 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_ALLOWLIST;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_SYSTEM;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_ALLOWLIST;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_DENYLIST;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_RESTRICTED_MODE;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -518,8 +505,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Defined UID policies. */ /** Defined UID policies. */
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray(); @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidRules = new SparseIntArray();
@GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray(); final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
@@ -598,6 +583,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock")
private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>(); private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>();
/** Objects used temporarily while computing the new blocked state for each uid. */
@GuardedBy("mUidRulesFirstLock")
private final SparseArray<UidBlockedState> mTmpUidBlockedState = new SparseArray<>();
/** Map from network ID to last observed meteredness state */ /** Map from network ID to last observed meteredness state */
@GuardedBy("mNetworkPoliciesSecondLock") @GuardedBy("mNetworkPoliciesSecondLock")
private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray(); private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray();
@@ -3825,7 +3814,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final SparseBooleanArray knownUids = new SparseBooleanArray(); final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids); collectKeys(mUidState, knownUids);
collectKeys(mUidRules, knownUids); collectKeys(mUidBlockedState, knownUids);
fout.println("Status for all known UIDs:"); fout.println("Status for all known UIDs:");
fout.increaseIndent(); fout.increaseIndent();
@@ -3843,23 +3832,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print(uidState.toString()); fout.print(uidState.toString());
} }
final int uidRules = mUidRules.get(uid, RULE_NONE); final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
fout.print(" rules="); if (uidBlockedState == null) {
fout.print(uidRulesToString(uidRules)); fout.print(" blocked_state={null}");
fout.println(); } else {
} fout.print(" blocked_state=");
fout.decreaseIndent(); fout.print(uidBlockedState.toString());
}
fout.println("Status for just UIDs with rules:");
fout.increaseIndent();
size = mUidRules.size();
for (int i = 0; i < size; i++) {
final int uid = mUidRules.keyAt(i);
fout.print("UID=");
fout.print(uid);
final int uidRules = mUidRules.get(uid, RULE_NONE);
fout.print(" rules=");
fout.print(uidRulesToString(uidRules));
fout.println(); fout.println();
} }
fout.decreaseIndent(); fout.decreaseIndent();
@@ -4010,22 +3989,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
void updateRestrictedModeAllowlistUL() { void updateRestrictedModeAllowlistUL() {
mUidFirewallRestrictedModeRules.clear(); mUidFirewallRestrictedModeRules.clear();
forEachUid("updateRestrictedModeAllowlist", uid -> { forEachUid("updateRestrictedModeAllowlist", uid -> {
final int oldUidRule = mUidRules.get(uid); synchronized (mUidRulesFirstLock) {
final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule); final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(
final boolean hasUidRuleChanged = oldUidRule != newUidRule; uid);
final int newFirewallRule = getRestrictedModeFirewallRule(newUidRule); final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState);
// setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
// non-default rules. // non-default rules.
if (newFirewallRule != FIREWALL_RULE_DEFAULT) { if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
mUidFirewallRestrictedModeRules.append(uid, newFirewallRule); mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
}
} }
if (hasUidRuleChanged) {
mUidRules.put(uid, newUidRule);
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
}
updateBlockedReasonsForRestrictedModeUL(uid);
}); });
if (mRestrictedNetworkingMode) { if (mRestrictedNetworkingMode) {
// firewall rules only need to be set when this mode is being enabled. // firewall rules only need to be set when this mode is being enabled.
@@ -4038,15 +4012,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@VisibleForTesting @VisibleForTesting
@GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock")
void updateRestrictedModeForUidUL(int uid) { void updateRestrictedModeForUidUL(int uid) {
final int oldUidRule = mUidRules.get(uid); final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid);
final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
final boolean hasUidRuleChanged = oldUidRule != newUidRule;
if (hasUidRuleChanged) {
mUidRules.put(uid, newUidRule);
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
}
updateBlockedReasonsForRestrictedModeUL(uid);
// if restricted networking mode is on, and the app has an access exemption, the uid rule // if restricted networking mode is on, and the app has an access exemption, the uid rule
// will not change, but the firewall rule will have to be updated. // will not change, but the firewall rule will have to be updated.
@@ -4054,16 +4020,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules. // Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
// In this case, default firewall rules can also be added. // In this case, default firewall rules can also be added.
setUidFirewallRule(FIREWALL_CHAIN_RESTRICTED, uid, setUidFirewallRule(FIREWALL_CHAIN_RESTRICTED, uid,
getRestrictedModeFirewallRule(newUidRule)); getRestrictedModeFirewallRule(uidBlockedState));
} }
} }
private void updateBlockedReasonsForRestrictedModeUL(int uid) { @GuardedBy("mUidRulesFirstLock")
UidBlockedState uidBlockedState = mUidBlockedState.get(uid); private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) {
if (uidBlockedState == null) { final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
uidBlockedState = new UidBlockedState(); mUidBlockedState, uid);
mUidBlockedState.put(uid, uidBlockedState);
}
final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
if (mRestrictedNetworkingMode) { if (mRestrictedNetworkingMode) {
uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE; uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
@@ -4077,23 +4041,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
uidBlockedState.updateEffectiveBlockedReasons(); uidBlockedState.updateEffectiveBlockedReasons();
if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, postBlockedReasonsChangedMsg(uid,
uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons) uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons);
.sendToTarget();
postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
} }
return uidBlockedState;
} }
private int getNewRestrictedModeUidRule(int uid, int oldUidRule) { private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) {
int newRule = oldUidRule; if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
newRule &= ~MASK_RESTRICTED_MODE_NETWORKS;
if (mRestrictedNetworkingMode && !hasRestrictedModeAccess(uid)) {
newRule |= RULE_REJECT_RESTRICTED_MODE;
}
return newRule;
}
private static int getRestrictedModeFirewallRule(int uidRule) {
if ((uidRule & RULE_REJECT_RESTRICTED_MODE) != 0) {
// rejected in restricted mode, this is the default behavior. // rejected in restricted mode, this is the default behavior.
return FIREWALL_RULE_DEFAULT; return FIREWALL_RULE_DEFAULT;
} else { } else {
@@ -4301,16 +4258,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (!isUidValidForDenylistRulesUL(uid)) { if (!isUidValidForDenylistRulesUL(uid)) {
continue; continue;
} }
int oldRules = mUidRules.get(uid); final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
if (enableChain) { mUidBlockedState, uid);
// Chain wasn't enabled before and the other power-related if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK)
// chains are allowlists, so we can clear the == BLOCKED_REASON_NONE) {
// MASK_ALL_NETWORKS part of the rules and re-inform listeners if // Chain isn't enabled and the uid had no restrictions to begin with.
// the effective rules result in blocking network access. continue;
oldRules &= MASK_METERED_NETWORKS;
} else {
// Skip if it had no restrictions to begin with
if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
} }
final boolean isUidIdle = !paroled && isUidIdle(uid); final boolean isUidIdle = !paroled && isUidIdle(uid);
if (isUidIdle && !mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid)) if (isUidIdle && !mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid))
@@ -4320,13 +4273,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else { } else {
mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DEFAULT); mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DEFAULT);
} }
final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, updateRulesForPowerRestrictionsUL(uid, isUidIdle);
isUidIdle);
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newUidRules);
}
} }
setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, blockedUids, setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, blockedUids,
enableChain ? CHAIN_TOGGLE_ENABLE : CHAIN_TOGGLE_DISABLE); enableChain ? CHAIN_TOGGLE_ENABLE : CHAIN_TOGGLE_DISABLE);
@@ -4544,6 +4491,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mInternetPermissionMap.put(uid, hasPermission); mInternetPermissionMap.put(uid, hasPermission);
return hasPermission; return hasPermission;
} catch (RemoteException e) { } catch (RemoteException e) {
// ignored; service lives in system_server
} }
return true; return true;
} }
@@ -4554,7 +4502,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock")
private void onUidDeletedUL(int uid) { private void onUidDeletedUL(int uid) {
// First cleanup in-memory state synchronously... // First cleanup in-memory state synchronously...
mUidRules.delete(uid); mUidBlockedState.delete(uid);
mUidPolicy.delete(uid); mUidPolicy.delete(uid);
mUidFirewallStandbyRules.delete(uid); mUidFirewallStandbyRules.delete(uid);
mUidFirewallDozableRules.delete(uid); mUidFirewallDozableRules.delete(uid);
@@ -4640,7 +4588,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* permission, since there is no need to change the {@code iptables} rule if the app does not * permission, since there is no need to change the {@code iptables} rule if the app does not
* have permission to use the internet. * have permission to use the internet.
* *
* <p>The {@link #mUidRules} map is used to define the transtion of states of an UID. * <p>The {@link #mUidBlockedState} map is used to define the transition of states of an UID.
* *
*/ */
private void updateRulesForDataUsageRestrictionsUL(int uid) { private void updateRulesForDataUsageRestrictionsUL(int uid) {
@@ -4655,6 +4603,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
} }
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForDataUsageRestrictionsULInner(int uid) { private void updateRulesForDataUsageRestrictionsULInner(int uid) {
if (!isUidValidForAllowlistRulesUL(uid)) { if (!isUidValidForAllowlistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid); if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
@@ -4662,38 +4611,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid); final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid); final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
UidBlockedState uidBlockedState = mUidBlockedState.get(uid); final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
if (uidBlockedState == null) { mUidBlockedState, uid);
uidBlockedState = new UidBlockedState(); final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
mUidBlockedState.put(uid, uidBlockedState); mTmpUidBlockedState, uid);
} previousUidBlockedState.copyFrom(uidBlockedState);
final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0;
// copy oldUidRules and clear out METERED_NETWORKS rules.
int newUidRules = oldUidRules & (~MASK_METERED_NETWORKS);
// First step: define the new rule based on user restrictions and foreground state.
if (isRestrictedByAdmin) {
newUidRules |= RULE_REJECT_METERED;
} else if (isForeground) {
if (isDenied || (mRestrictBackground && !isAllowed)) {
newUidRules |= RULE_TEMPORARY_ALLOW_METERED;
} else if (isAllowed) {
newUidRules |= RULE_ALLOW_METERED;
}
} else {
if (isDenied) {
newUidRules |= RULE_REJECT_METERED;
} else if (mRestrictBackground && isAllowed) {
newUidRules |= RULE_ALLOW_METERED;
}
}
int newBlockedReasons = BLOCKED_REASON_NONE; int newBlockedReasons = BLOCKED_REASON_NONE;
int newAllowedReasons = ALLOWED_REASON_NONE; int newAllowedReasons = ALLOWED_REASON_NONE;
newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0); newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0);
@@ -4704,16 +4632,48 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0); newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0);
newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0); newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0);
uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
& ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
& ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
uidBlockedState.updateEffectiveBlockedReasons();
final int oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons;
final int newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) {
postBlockedReasonsChangedMsg(uid,
newEffectiveBlockedReasons, oldEffectiveBlockedReasons);
postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
}
// Note that the conditionals below are for avoiding unnecessary calls to netd.
// TODO: Measure the performance for doing a no-op call to netd so that we can
// remove the conditionals to simplify the logic below. We can also further reduce
// some calls to netd if they turn out to be costly.
final int denylistReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
| BLOCKED_METERED_REASON_USER_RESTRICTED;
if ((oldEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE
|| (newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE) {
setMeteredNetworkDenylist(uid,
(newEffectiveBlockedReasons & denylistReasons) != BLOCKED_REASON_NONE);
}
final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND
| ALLOWED_METERED_REASON_USER_EXEMPTED;
final int oldAllowedReasons = previousUidBlockedState.allowedReasons;
if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE
|| (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) {
setMeteredNetworkAllowlist(uid,
(newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE);
}
if (LOGV) { if (LOGV) {
Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ ": isForeground=" +isForeground + ": isForeground=" +isForeground
+ ", isDenied=" + isDenied + ", isDenied=" + isDenied
+ ", isAllowed=" + isAllowed + ", isAllowed=" + isAllowed
+ ", isRestrictedByAdmin=" + isRestrictedByAdmin + ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ ", oldRule=" + uidRulesToString(oldUidRules & MASK_METERED_NETWORKS) + ", oldBlockedState=" + previousUidBlockedState.toString()
+ ", newRule=" + uidRulesToString(newUidRules & MASK_METERED_NETWORKS) + ", newBlockedState="
+ ", newUidRules=" + uidRulesToString(newUidRules)
+ ", oldUidRules=" + uidRulesToString(oldUidRules)
+ ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString( + ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK) uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
+ ", oldBlockedMeteredEffectiveReasons=" + ", oldBlockedMeteredEffectiveReasons="
@@ -4722,84 +4682,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString( + ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK)); uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK));
} }
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newUidRules);
}
// Second step: apply bw changes based on change of state.
if (newUidRules != oldUidRules) {
if (hasRule(newUidRules, RULE_TEMPORARY_ALLOW_METERED)) {
// Temporarily allow foreground app, removing from denylist if necessary
// (since bw_penalty_box prevails over bw_happy_box).
setMeteredNetworkAllowlist(uid, true);
// TODO: if statement below is used to avoid an unnecessary call to netd / iptables,
// but ideally it should be just:
// setMeteredNetworkDenylist(uid, isDenied);
if (isDenied) {
setMeteredNetworkDenylist(uid, false);
}
} else if (hasRule(oldUidRules, RULE_TEMPORARY_ALLOW_METERED)) {
// Remove temporary exemption from app that is not on foreground anymore.
// TODO: if statements below are used to avoid unnecessary calls to netd / iptables,
// but ideally they should be just:
// setMeteredNetworkAllowlist(uid, isAllowed);
// setMeteredNetworkDenylist(uid, isDenied);
if (!isAllowed) {
setMeteredNetworkAllowlist(uid, false);
}
if (isDenied || isRestrictedByAdmin) {
setMeteredNetworkDenylist(uid, true);
}
} else if (hasRule(newUidRules, RULE_REJECT_METERED)
|| hasRule(oldUidRules, RULE_REJECT_METERED)) {
// Flip state because app was explicitly added or removed to denylist.
setMeteredNetworkDenylist(uid, (isDenied || isRestrictedByAdmin));
if (hasRule(oldUidRules, RULE_REJECT_METERED) && isAllowed) {
// Since denial prevails over allowance, we need to handle the special case
// where app is allowed and denied at the same time (although such
// scenario should be blocked by the UI), then it is removed from the denylist.
setMeteredNetworkAllowlist(uid, isAllowed);
}
} else if (hasRule(newUidRules, RULE_ALLOW_METERED)
|| hasRule(oldUidRules, RULE_ALLOW_METERED)) {
// Flip state because app was explicitly added or removed to allowlist.
setMeteredNetworkAllowlist(uid, isAllowed);
} else {
// All scenarios should have been covered above.
Log.wtf(TAG, "Unexpected change of metered UID state for " + uid
+ ": foreground=" + isForeground
+ ", allowlisted=" + isAllowed
+ ", denylisted=" + isDenied
+ ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ ", newRule=" + uidRulesToString(newUidRules)
+ ", oldRule=" + uidRulesToString(oldUidRules));
}
// Dispatch changed rule to existing listeners.
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
}
final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
& ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
& ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
uidBlockedState.updateEffectiveBlockedReasons();
if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
.sendToTarget();
}
} }
/** /**
* Updates the power-related part of the {@link #mUidRules} for a given map, and notify external * Updates the power-related part of the {@link #mUidBlockedState} for a given map, and
* listeners in case of change. * notify external listeners in case of change.
* <p> * <p>
* There are 3 power-related rules that affects whether an app has background access on * There are 3 power-related rules that affects whether an app has background access on
* non-metered networks, and when the condition applies and the UID is not allowed for power * non-metered networks, and when the condition applies and the UID is not allowed for power
@@ -4810,23 +4697,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* <li>Battery Saver Mode is on: {@code fw_powersave} firewall chain. * <li>Battery Saver Mode is on: {@code fw_powersave} firewall chain.
* </ul> * </ul>
* <p> * <p>
* This method updates the power-related part of the {@link #mUidRules} for a given uid based on * This method updates the power-related part of the {@link #mUidBlockedState} for a given
* these modes, the UID process state (foreground or not), and the UID allowlist state. * uid based on these modes, the UID process state (foreground or not), and the UID
* allowlist state.
* <p> * <p>
* <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}. * <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
*/ */
@GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock")
private void updateRulesForPowerRestrictionsUL(int uid) { private void updateRulesForPowerRestrictionsUL(int uid) {
final int oldUidRules = mUidRules.get(uid, RULE_NONE); updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid));
final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules,
isUidIdle(uid));
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newUidRules);
}
} }
/** /**
@@ -4835,56 +4714,37 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* @param uid the uid of the app to update rules for * @param uid the uid of the app to update rules for
* @param oldUidRules the current rules for the uid, in order to determine if there's a change * @param oldUidRules the current rules for the uid, in order to determine if there's a change
* @param isUidIdle whether uid is idle or not * @param isUidIdle whether uid is idle or not
*
* @return the new computed rules for the uid
*/ */
@GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock")
private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean isUidIdle) { private void updateRulesForPowerRestrictionsUL(int uid, boolean isUidIdle) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
"updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/" "updateRulesForPowerRestrictionsUL: " + uid + "/"
+ (isUidIdle ? "I" : "-")); + (isUidIdle ? "I" : "-"));
} }
try { try {
return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, isUidIdle); updateRulesForPowerRestrictionsULInner(uid, isUidIdle);
} finally { } finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK); Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
} }
} }
@GuardedBy("mUidRulesFirstLock") @GuardedBy("mUidRulesFirstLock")
private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, private void updateRulesForPowerRestrictionsULInner(int uid, boolean isUidIdle) {
boolean isUidIdle) {
if (!isUidValidForDenylistRulesUL(uid)) { if (!isUidValidForDenylistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid); if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
return RULE_NONE; return;
} }
final boolean restrictMode = isUidIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid); final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode); final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
// Copy existing uid rules and clear ALL_NETWORK rules. final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS); mUidBlockedState, uid);
final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
UidBlockedState uidBlockedState = mUidBlockedState.get(uid); mTmpUidBlockedState, uid);
if (uidBlockedState == null) { previousUidBlockedState.copyFrom(uidBlockedState);
uidBlockedState = new UidBlockedState();
mUidBlockedState.put(uid, uidBlockedState);
}
// First step: define the new rule based on user restrictions and foreground state.
// NOTE: if statements below could be inlined, but it's easier to understand the logic
// by considering the foreground and non-foreground states.
if (isForeground) {
if (restrictMode) {
newUidRules |= RULE_ALLOW_ALL;
}
} else if (restrictMode) {
newUidRules |= isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
}
int newBlockedReasons = BLOCKED_REASON_NONE; int newBlockedReasons = BLOCKED_REASON_NONE;
int newAllowedReasons = ALLOWED_REASON_NONE; int newAllowedReasons = ALLOWED_REASON_NONE;
@@ -4900,6 +4760,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid) newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0); ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
& BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
& ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
uidBlockedState.updateEffectiveBlockedReasons();
if (previousUidBlockedState.effectiveBlockedReasons
!= uidBlockedState.effectiveBlockedReasons) {
postBlockedReasonsChangedMsg(uid,
uidBlockedState.effectiveBlockedReasons,
previousUidBlockedState.effectiveBlockedReasons);
postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
}
if (LOGV) { if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")" Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
+ ", isIdle: " + isUidIdle + ", isIdle: " + isUidIdle
@@ -4907,43 +4781,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ ", mDeviceIdleMode: " + mDeviceIdleMode + ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground + ", isForeground=" + isForeground
+ ", isWhitelisted=" + isWhitelisted + ", isWhitelisted=" + isWhitelisted
+ ", oldRule=" + uidRulesToString(oldUidRules & MASK_ALL_NETWORKS) + ", oldUidBlockedState=" + previousUidBlockedState.toString()
+ ", newRule=" + uidRulesToString(newUidRules & MASK_ALL_NETWORKS) + ", newUidBlockedState=" + uidBlockedState.toString());
+ ", newUidRules=" + uidRulesToString(newUidRules)
+ ", oldUidRules=" + uidRulesToString(oldUidRules));
} }
// Second step: notify listeners if state changed.
if (newUidRules != oldUidRules) {
if ((newUidRules & MASK_ALL_NETWORKS) == RULE_NONE || hasRule(newUidRules,
RULE_ALLOW_ALL)) {
if (LOGV) Log.v(TAG, "Allowing non-metered access for UID " + uid);
} else if (hasRule(newUidRules, RULE_REJECT_ALL)) {
if (LOGV) Log.v(TAG, "Rejecting non-metered access for UID " + uid);
} else {
// All scenarios should have been covered above
Log.wtf(TAG, "Unexpected change of non-metered UID state for " + uid
+ ": foreground=" + isForeground
+ ", whitelisted=" + isWhitelisted
+ ", newRule=" + uidRulesToString(newUidRules)
+ ", oldRule=" + uidRulesToString(oldUidRules));
}
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget();
}
final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons
& BLOCKED_METERED_REASON_MASK) | newBlockedReasons;
uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons
& ALLOWED_METERED_REASON_MASK) | newAllowedReasons;
uidBlockedState.updateEffectiveBlockedReasons();
if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
.sendToTarget();
}
return newUidRules;
} }
private class NetPolicyAppIdleStateChangeListener extends AppIdleStateChangeListener { private class NetPolicyAppIdleStateChangeListener extends AppIdleStateChangeListener {
@@ -4971,10 +4811,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
} }
private void postBlockedReasonsChangedMsg(int uid, int newEffectiveBlockedReasons,
int oldEffectiveBlockedReasons) {
mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
newEffectiveBlockedReasons, oldEffectiveBlockedReasons)
.sendToTarget();
}
private void postUidRulesChangedMsg(int uid, int uidRules) {
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules)
.sendToTarget();
}
private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
try { try {
listener.onUidRulesChanged(uid, uidRules); listener.onUidRulesChanged(uid, uidRules);
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
} }
} }
@@ -4983,6 +4836,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try { try {
listener.onMeteredIfacesChanged(meteredIfaces); listener.onMeteredIfacesChanged(meteredIfaces);
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
} }
} }
@@ -4991,6 +4845,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try { try {
listener.onRestrictBackgroundChanged(restrictBackground); listener.onRestrictBackgroundChanged(restrictBackground);
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
} }
} }
@@ -4999,6 +4854,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try { try {
listener.onUidPoliciesChanged(uid, uidPolicies); listener.onUidPoliciesChanged(uid, uidPolicies);
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
} }
} }
@@ -5007,6 +4863,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try { try {
listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes); listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
} }
} }
@@ -5015,6 +4872,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try { try {
listener.onSubscriptionPlansChanged(subId, plans); listener.onSubscriptionPlansChanged(subId, plans);
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
} }
} }
@@ -5023,6 +4881,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try { try {
listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons); listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons);
} catch (RemoteException ignored) { } catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
} }
} }
@@ -5033,6 +4892,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case MSG_RULES_CHANGED: { case MSG_RULES_CHANGED: {
final int uid = msg.arg1; final int uid = msg.arg1;
final int uidRules = msg.arg2; final int uidRules = msg.arg2;
if (LOGV) {
Slog.v(TAG, "Dispatching rules=" + uidRulesToString(uidRules)
+ " for uid=" + uid);
}
final int length = mListeners.beginBroadcast(); final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -5605,7 +5468,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
} }
private static void collectKeys(SparseArray<UidState> source, SparseBooleanArray target) { private static <T> void collectKeys(SparseArray<T> source, SparseBooleanArray target) {
final int size = source.size(); final int size = source.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
target.put(source.keyAt(i), true); target.put(source.keyAt(i), true);
@@ -5653,90 +5516,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long startTime = mStatLogger.getTime(); final long startTime = mStatLogger.getTime();
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG); mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules; int blockedReasons;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) { synchronized (mUidRulesFirstLock) {
uidRules = mUidRules.get(uid, RULE_NONE); final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
isBackgroundRestricted = mRestrictBackground; blockedReasons = uidBlockedState == null
? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
if (!isNetworkMetered) {
blockedReasons &= ~BLOCKED_METERED_REASON_MASK;
}
mLogger.networkBlocked(uid, uidBlockedState);
} }
final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
isBackgroundRestricted, mLogger);
mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime); mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime);
return ret; return blockedReasons != BLOCKED_REASON_NONE;
} }
@Override @Override
public boolean isUidRestrictedOnMeteredNetworks(int uid) { public boolean isUidRestrictedOnMeteredNetworks(int uid) {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG); mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) { synchronized (mUidRulesFirstLock) {
uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
isBackgroundRestricted = mRestrictBackground; int blockedReasons = uidBlockedState == null
? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons;
blockedReasons &= BLOCKED_METERED_REASON_MASK;
return blockedReasons != BLOCKED_REASON_NONE;
} }
// TODO(b/177490332): The logic here might not be correct because it doesn't consider
// RULE_REJECT_METERED condition. And it could be replaced by
// isUidNetworkingBlockedInternal().
return isBackgroundRestricted
&& !hasRule(uidRules, RULE_ALLOW_METERED)
&& !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
} }
private static boolean isSystem(int uid) { private static boolean isSystem(int uid) {
return uid < Process.FIRST_APPLICATION_UID; return uid < Process.FIRST_APPLICATION_UID;
} }
static boolean isUidNetworkingBlockedInternal(int uid, int uidRules, boolean isNetworkMetered,
boolean isBackgroundRestricted, @Nullable NetworkPolicyLogger logger) {
final int reason;
// Networks are never blocked for system components
if (isSystem(uid)) {
reason = NTWK_ALLOWED_SYSTEM;
} else if (hasRule(uidRules, RULE_REJECT_RESTRICTED_MODE)) {
reason = NTWK_BLOCKED_RESTRICTED_MODE;
} else if (hasRule(uidRules, RULE_REJECT_ALL)) {
reason = NTWK_BLOCKED_POWER;
} else if (!isNetworkMetered) {
reason = NTWK_ALLOWED_NON_METERED;
} else if (hasRule(uidRules, RULE_REJECT_METERED)) {
reason = NTWK_BLOCKED_DENYLIST;
} else if (hasRule(uidRules, RULE_ALLOW_METERED)) {
reason = NTWK_ALLOWED_ALLOWLIST;
} else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
reason = NTWK_ALLOWED_TMP_ALLOWLIST;
} else if (isBackgroundRestricted) {
reason = NTWK_BLOCKED_BG_RESTRICT;
} else {
reason = NTWK_ALLOWED_DEFAULT;
}
final boolean blocked;
switch(reason) {
case NTWK_ALLOWED_DEFAULT:
case NTWK_ALLOWED_NON_METERED:
case NTWK_ALLOWED_TMP_ALLOWLIST:
case NTWK_ALLOWED_ALLOWLIST:
case NTWK_ALLOWED_SYSTEM:
blocked = false;
break;
case NTWK_BLOCKED_RESTRICTED_MODE:
case NTWK_BLOCKED_POWER:
case NTWK_BLOCKED_DENYLIST:
case NTWK_BLOCKED_BG_RESTRICT:
blocked = true;
break;
default:
throw new IllegalArgumentException();
}
if (logger != null) {
logger.networkBlocked(uid, reason);
}
return blocked;
}
private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal { private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
@Override @Override
@@ -5945,6 +5756,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue; return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
} }
private static UidBlockedState getOrCreateUidBlockedStateForUid(
SparseArray<UidBlockedState> uidBlockedStates, int uid) {
UidBlockedState uidBlockedState = uidBlockedStates.get(uid);
if (uidBlockedState == null) {
uidBlockedState = new UidBlockedState();
uidBlockedStates.put(uid, uidBlockedState);
}
return uidBlockedState;
}
@VisibleForTesting @VisibleForTesting
static final class UidBlockedState { static final class UidBlockedState {
public int blockedReasons; public int blockedReasons;
@@ -6008,9 +5829,180 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
return effectiveBlockedReasons; return effectiveBlockedReasons;
} }
@Override
public String toString() {
return toString(blockedReasons, allowedReasons, effectiveBlockedReasons);
}
public static String toString(int blockedReasons, int allowedReasons,
int effectiveBlockedReasons) {
final StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("blocked=").append(blockedReasonsToString(blockedReasons)).append(",");
sb.append("allowed=").append(allowedReasonsToString(allowedReasons)).append(",");
sb.append("effective=").append(blockedReasonsToString(effectiveBlockedReasons));
sb.append("}");
return sb.toString();
}
private static final int[] BLOCKED_REASONS = {
BLOCKED_REASON_BATTERY_SAVER,
BLOCKED_REASON_DOZE,
BLOCKED_REASON_APP_STANDBY,
BLOCKED_REASON_RESTRICTED_MODE,
BLOCKED_METERED_REASON_DATA_SAVER,
BLOCKED_METERED_REASON_USER_RESTRICTED,
BLOCKED_METERED_REASON_ADMIN_DISABLED,
};
private static final int[] ALLOWED_REASONS = {
ALLOWED_REASON_SYSTEM,
ALLOWED_REASON_FOREGROUND,
ALLOWED_REASON_POWER_SAVE_ALLOWLIST,
ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST,
ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS,
ALLOWED_METERED_REASON_USER_EXEMPTED,
ALLOWED_METERED_REASON_SYSTEM,
ALLOWED_METERED_REASON_FOREGROUND,
};
private static String blockedReasonToString(int blockedReason) {
switch (blockedReason) {
case BLOCKED_REASON_NONE:
return "NONE";
case BLOCKED_REASON_BATTERY_SAVER:
return "BATTERY_SAVER";
case BLOCKED_REASON_DOZE:
return "DOZE";
case BLOCKED_REASON_APP_STANDBY:
return "APP_STANDBY";
case BLOCKED_REASON_RESTRICTED_MODE:
return "RESTRICTED_MODE";
case BLOCKED_METERED_REASON_DATA_SAVER:
return "DATA_SAVER";
case BLOCKED_METERED_REASON_USER_RESTRICTED:
return "METERED_USER_RESTRICTED";
case BLOCKED_METERED_REASON_ADMIN_DISABLED:
return "METERED_ADMIN_DISABLED";
default:
Slog.wtfStack(TAG, "Unknown blockedReason: " + blockedReason);
return String.valueOf(blockedReason);
}
}
private static String allowedReasonToString(int allowedReason) {
switch (allowedReason) {
case ALLOWED_REASON_NONE:
return "NONE";
case ALLOWED_REASON_SYSTEM:
return "SYSTEM";
case ALLOWED_REASON_FOREGROUND:
return "FOREGROUND";
case ALLOWED_REASON_POWER_SAVE_ALLOWLIST:
return "POWER_SAVE_ALLOWLIST";
case ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST:
return "POWER_SAVE_EXCEPT_IDLE_ALLOWLIST";
case ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS:
return "RESTRICTED_MODE_PERMISSIONS";
case ALLOWED_METERED_REASON_USER_EXEMPTED:
return "METERED_USER_EXEMPTED";
case ALLOWED_METERED_REASON_SYSTEM:
return "METERED_SYSTEM";
case ALLOWED_METERED_REASON_FOREGROUND:
return "METERED_FOREGROUND";
default:
Slog.wtfStack(TAG, "Unknown allowedReason: " + allowedReason);
return String.valueOf(allowedReason);
}
}
public static String blockedReasonsToString(int blockedReasons) {
if (blockedReasons == BLOCKED_REASON_NONE) {
return blockedReasonToString(BLOCKED_REASON_NONE);
}
final StringBuilder sb = new StringBuilder();
for (int reason : BLOCKED_REASONS) {
if ((blockedReasons & reason) != 0) {
sb.append(sb.length() == 0 ? "" : "|");
sb.append(blockedReasonToString(reason));
blockedReasons &= ~reason;
}
}
if (blockedReasons != 0) {
sb.append(sb.length() == 0 ? "" : "|");
sb.append(String.valueOf(blockedReasons));
Slog.wtfStack(TAG, "Unknown blockedReasons: " + blockedReasons);
}
return sb.toString();
}
public static String allowedReasonsToString(int allowedReasons) {
if (allowedReasons == ALLOWED_REASON_NONE) {
return allowedReasonToString(ALLOWED_REASON_NONE);
}
final StringBuilder sb = new StringBuilder();
for (int reason : ALLOWED_REASONS) {
if ((allowedReasons & reason) != 0) {
sb.append(sb.length() == 0 ? "" : "|");
sb.append(allowedReasonToString(reason));
allowedReasons &= ~reason;
}
}
if (allowedReasons != 0) {
sb.append(sb.length() == 0 ? "" : "|");
sb.append(String.valueOf(allowedReasons));
Slog.wtfStack(TAG, "Unknown allowedReasons: " + allowedReasons);
}
return sb.toString();
}
public void copyFrom(UidBlockedState uidBlockedState) {
blockedReasons = uidBlockedState.blockedReasons;
allowedReasons = uidBlockedState.allowedReasons;
effectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
}
public int deriveUidRules() {
int uidRule = RULE_NONE;
if ((effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
uidRule |= RULE_REJECT_RESTRICTED_MODE;
}
int powerBlockedReasons = BLOCKED_REASON_APP_STANDBY
| BLOCKED_REASON_DOZE
| BLOCKED_REASON_BATTERY_SAVER;
if ((effectiveBlockedReasons & powerBlockedReasons) != 0) {
uidRule |= RULE_REJECT_ALL;
} else if ((blockedReasons & powerBlockedReasons) != 0) {
uidRule |= RULE_ALLOW_ALL;
}
// UidRule doesn't include RestrictBackground (DataSaver) state, so not including in
// metered blocked reasons below.
int meteredBlockedReasons = BLOCKED_METERED_REASON_ADMIN_DISABLED
| BLOCKED_METERED_REASON_USER_RESTRICTED;
if ((effectiveBlockedReasons & meteredBlockedReasons) != 0) {
uidRule |= RULE_REJECT_METERED;
} else if ((blockedReasons & BLOCKED_METERED_REASON_USER_RESTRICTED) != 0
&& (allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) {
uidRule |= RULE_TEMPORARY_ALLOW_METERED;
} else if ((blockedReasons & BLOCKED_METERED_REASON_DATA_SAVER) != 0) {
if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
uidRule |= RULE_ALLOW_ALL;
} else if ((allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) {
uidRule |= RULE_TEMPORARY_ALLOW_METERED;
}
}
if (LOGV) {
Slog.v(TAG, "uidBlockedState=" + this.toString()
+ " -> uidRule=" + uidRulesToString(uidRule));
}
return uidRule;
}
} }
private class NotificationId { private static class NotificationId {
private final String mTag; private final String mTag;
private final int mId; private final int mId;