Merge changes Ifc3708c1,If07045c1 am: 61c79dbc8d

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1902411

Change-Id: Ibeaec84460b6953ce6567e8694f3d1593d714253
This commit is contained in:
Sudheer Shanka
2021-11-25 04:48:16 +00:00
committed by Automerger Merge Worker
2 changed files with 231 additions and 397 deletions

View File

@@ -39,6 +39,7 @@ import android.util.Slog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.RingBuffer;
import com.android.server.am.ProcessList;
import com.android.server.net.NetworkPolicyManagerService.UidBlockedState;
import java.text.SimpleDateFormat;
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_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 mUidStateChangeBuffer = 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();
void networkBlocked(int uid, int reason) {
void networkBlocked(int uid, UidBlockedState uidBlockedState) {
synchronized (mLock) {
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) {
return "Policy for " + uid + " changed from "
+ NetworkPolicyManager.uidPoliciesToString(oldPolicy) + " to "
@@ -402,14 +371,17 @@ public class NetworkPolicyLogger {
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();
if (data == null) return;
data.reset();
data.type = EVENT_NETWORK_BLOCKED;
data.ifield1 = uid;
data.ifield2 = reason;
data.ifield2 = blockedReasons;
data.ifield3 = allowedReasons;
data.ifield4 = effectiveBlockedReasons;
data.timeStamp = System.currentTimeMillis();
}
@@ -554,7 +526,8 @@ public class NetworkPolicyLogger {
case EVENT_TYPE_GENERIC:
return data.sfield1;
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:
return data.ifield1 + ":" + ProcessList.makeProcStateString(data.ifield2)
+ ":" + ActivityManager.getCapabilitiesSummary(data.ifield3)
@@ -593,17 +566,18 @@ public class NetworkPolicyLogger {
}
}
public final static class Data {
int type;
long timeStamp;
private static final class Data {
public int type;
public long timeStamp;
int ifield1;
int ifield2;
int ifield3;
long lfield1;
boolean bfield1;
boolean bfield2;
String sfield1;
public int ifield1;
public int ifield2;
public int ifield3;
public int ifield4;
public long lfield1;
public boolean bfield1;
public boolean bfield2;
public String sfield1;
public void reset(){
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.EXTRA_NETWORK_TEMPLATE;
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_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
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_REJECT_ALL;
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.writeStringAttribute;
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 org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -518,8 +505,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Defined UID policies. */
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
@GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidRules = new SparseIntArray();
@GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
@@ -598,6 +583,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
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 */
@GuardedBy("mNetworkPoliciesSecondLock")
private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray();
@@ -3825,7 +3814,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final SparseBooleanArray knownUids = new SparseBooleanArray();
collectKeys(mUidState, knownUids);
collectKeys(mUidRules, knownUids);
collectKeys(mUidBlockedState, knownUids);
fout.println("Status for all known UIDs:");
@@ -3844,10 +3832,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print(uidState.toString());
}
final int uidRules = mUidRules.get(uid, RULE_NONE);
fout.print(" rules=");
fout.print(uidRulesToString(uidRules));
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
if (uidBlockedState == null) {
fout.print(" blocked_state={null}");
@@ -3859,20 +3843,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
fout.decreaseIndent();
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.decreaseIndent();
fout.println("Admin restricted uids for metered data:");
fout.increaseIndent();
size = mMeteredRestrictedUids.size();
@@ -4019,22 +3989,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
void updateRestrictedModeAllowlistUL() {
mUidFirewallRestrictedModeRules.clear();
forEachUid("updateRestrictedModeAllowlist", uid -> {
final int oldUidRule = mUidRules.get(uid);
final int newUidRule = getNewRestrictedModeUidRule(uid, oldUidRule);
final boolean hasUidRuleChanged = oldUidRule != newUidRule;
final int newFirewallRule = getRestrictedModeFirewallRule(newUidRule);
synchronized (mUidRulesFirstLock) {
final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(
uid);
final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState);
// setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
// non-default rules.
if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
// setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add
// non-default rules.
if (newFirewallRule != FIREWALL_RULE_DEFAULT) {
mUidFirewallRestrictedModeRules.append(uid, newFirewallRule);
}
}
if (hasUidRuleChanged) {
mUidRules.put(uid, newUidRule);
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget();
}
updateBlockedReasonsForRestrictedModeUL(uid);
});
if (mRestrictedNetworkingMode) {
// firewall rules only need to be set when this mode is being enabled.
@@ -4047,15 +4012,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@VisibleForTesting
@GuardedBy("mUidRulesFirstLock")
void updateRestrictedModeForUidUL(int uid) {
final int oldUidRule = mUidRules.get(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);
final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid);
// 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.
@@ -4063,16 +4020,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules.
// In this case, default firewall rules can also be added.
setUidFirewallRule(FIREWALL_CHAIN_RESTRICTED, uid,
getRestrictedModeFirewallRule(newUidRule));
getRestrictedModeFirewallRule(uidBlockedState));
}
}
private void updateBlockedReasonsForRestrictedModeUL(int uid) {
UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
if (uidBlockedState == null) {
uidBlockedState = new UidBlockedState();
mUidBlockedState.put(uid, uidBlockedState);
}
@GuardedBy("mUidRulesFirstLock")
private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) {
final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
mUidBlockedState, uid);
final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons;
if (mRestrictedNetworkingMode) {
uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE;
@@ -4086,23 +4041,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
uidBlockedState.updateEffectiveBlockedReasons();
if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid,
uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons)
.sendToTarget();
postBlockedReasonsChangedMsg(uid,
uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons);
postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules());
}
return uidBlockedState;
}
private int getNewRestrictedModeUidRule(int uid, int oldUidRule) {
int newRule = oldUidRule;
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) {
private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) {
if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) {
// rejected in restricted mode, this is the default behavior.
return FIREWALL_RULE_DEFAULT;
} else {
@@ -4310,16 +4258,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (!isUidValidForDenylistRulesUL(uid)) {
continue;
}
int oldRules = mUidRules.get(uid);
if (enableChain) {
// Chain wasn't enabled before and the other power-related
// chains are allowlists, so we can clear the
// MASK_ALL_NETWORKS part of the rules and re-inform listeners if
// the effective rules result in blocking network access.
oldRules &= MASK_METERED_NETWORKS;
} else {
// Skip if it had no restrictions to begin with
if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
mUidBlockedState, uid);
if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK)
== BLOCKED_REASON_NONE) {
// Chain isn't enabled and the uid had no restrictions to begin with.
continue;
}
final boolean isUidIdle = !paroled && isUidIdle(uid);
if (isUidIdle && !mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid))
@@ -4329,13 +4273,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} else {
mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DEFAULT);
}
final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules,
isUidIdle);
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newUidRules);
}
updateRulesForPowerRestrictionsUL(uid, isUidIdle);
}
setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, blockedUids,
enableChain ? CHAIN_TOGGLE_ENABLE : CHAIN_TOGGLE_DISABLE);
@@ -4553,6 +4491,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mInternetPermissionMap.put(uid, hasPermission);
return hasPermission;
} catch (RemoteException e) {
// ignored; service lives in system_server
}
return true;
}
@@ -4563,7 +4502,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
private void onUidDeletedUL(int uid) {
// First cleanup in-memory state synchronously...
mUidRules.delete(uid);
mUidBlockedState.delete(uid);
mUidPolicy.delete(uid);
mUidFirewallStandbyRules.delete(uid);
@@ -4650,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
* 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) {
@@ -4665,6 +4603,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForDataUsageRestrictionsULInner(int uid) {
if (!isUidValidForAllowlistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
@@ -4672,38 +4611,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid);
final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid);
UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
if (uidBlockedState == null) {
uidBlockedState = new UidBlockedState();
mUidBlockedState.put(uid, uidBlockedState);
}
final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
mUidBlockedState, uid);
final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
mTmpUidBlockedState, uid);
previousUidBlockedState.copyFrom(uidBlockedState);
final boolean isDenied = (uidPolicy & POLICY_REJECT_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 newAllowedReasons = ALLOWED_REASON_NONE;
newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0);
@@ -4714,16 +4632,48 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 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) {
Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")"
+ ": isForeground=" +isForeground
+ ", isDenied=" + isDenied
+ ", isAllowed=" + isAllowed
+ ", isRestrictedByAdmin=" + isRestrictedByAdmin
+ ", oldRule=" + uidRulesToString(oldUidRules & MASK_METERED_NETWORKS)
+ ", newRule=" + uidRulesToString(newUidRules & MASK_METERED_NETWORKS)
+ ", newUidRules=" + uidRulesToString(newUidRules)
+ ", oldUidRules=" + uidRulesToString(oldUidRules)
+ ", oldBlockedState=" + previousUidBlockedState.toString()
+ ", newBlockedState="
+ ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK)
+ ", oldBlockedMeteredEffectiveReasons="
@@ -4732,84 +4682,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString(
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
* listeners in case of change.
* Updates the power-related part of the {@link #mUidBlockedState} for a given map, and
* notify external listeners in case of change.
* <p>
* 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
@@ -4820,23 +4697,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* <li>Battery Saver Mode is on: {@code fw_powersave} firewall chain.
* </ul>
* <p>
* This method updates the power-related part of the {@link #mUidRules} for a given uid based on
* these modes, the UID process state (foreground or not), and the UID allowlist state.
* This method updates the power-related part of the {@link #mUidBlockedState} for a given
* uid based on these modes, the UID process state (foreground or not), and the UID
* allowlist state.
* <p>
* <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}.
*/
@GuardedBy("mUidRulesFirstLock")
private void updateRulesForPowerRestrictionsUL(int uid) {
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules,
isUidIdle(uid));
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newUidRules);
}
updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid));
}
/**
@@ -4845,56 +4714,37 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* @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 isUidIdle whether uid is idle or not
*
* @return the new computed rules for the uid
*/
@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)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
"updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
"updateRulesForPowerRestrictionsUL: " + uid + "/"
+ (isUidIdle ? "I" : "-"));
}
try {
return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, isUidIdle);
updateRulesForPowerRestrictionsULInner(uid, isUidIdle);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
@GuardedBy("mUidRulesFirstLock")
private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules,
boolean isUidIdle) {
private void updateRulesForPowerRestrictionsULInner(int uid, boolean isUidIdle) {
if (!isUidValidForDenylistRulesUL(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 isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
// Copy existing uid rules and clear ALL_NETWORK rules.
int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS);
UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
if (uidBlockedState == null) {
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;
}
final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid(
mUidBlockedState, uid);
final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid(
mTmpUidBlockedState, uid);
previousUidBlockedState.copyFrom(uidBlockedState);
int newBlockedReasons = BLOCKED_REASON_NONE;
int newAllowedReasons = ALLOWED_REASON_NONE;
@@ -4910,6 +4760,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
? 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) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
+ ", isIdle: " + isUidIdle
@@ -4917,43 +4781,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground
+ ", isWhitelisted=" + isWhitelisted
+ ", oldRule=" + uidRulesToString(oldUidRules & MASK_ALL_NETWORKS)
+ ", newRule=" + uidRulesToString(newUidRules & MASK_ALL_NETWORKS)
+ ", newUidRules=" + uidRulesToString(newUidRules)
+ ", oldUidRules=" + uidRulesToString(oldUidRules));
+ ", oldUidBlockedState=" + previousUidBlockedState.toString()
+ ", newUidBlockedState=" + uidBlockedState.toString());
}
// 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 {
@@ -4981,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) {
try {
listener.onUidRulesChanged(uid, uidRules);
} catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
}
}
@@ -4993,6 +4836,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onMeteredIfacesChanged(meteredIfaces);
} catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
}
}
@@ -5001,6 +4845,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onRestrictBackgroundChanged(restrictBackground);
} catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
}
}
@@ -5009,6 +4854,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onUidPoliciesChanged(uid, uidPolicies);
} catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
}
}
@@ -5017,6 +4863,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes);
} catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
}
}
@@ -5025,6 +4872,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onSubscriptionPlansChanged(subId, plans);
} catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
}
}
@@ -5033,6 +4881,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons);
} catch (RemoteException ignored) {
// Ignore if there is an error sending the callback to the client.
}
}
@@ -5043,6 +4892,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case MSG_RULES_CHANGED: {
final int uid = msg.arg1;
final int uidRules = msg.arg2;
if (LOGV) {
Slog.v(TAG, "Dispatching rules=" + uidRulesToString(uidRules)
+ " for uid=" + uid);
}
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
@@ -5663,90 +5516,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long startTime = mStatLogger.getTime();
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
final boolean isBackgroundRestricted;
int blockedReasons;
synchronized (mUidRulesFirstLock) {
uidRules = mUidRules.get(uid, RULE_NONE);
isBackgroundRestricted = mRestrictBackground;
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
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);
return ret;
return blockedReasons != BLOCKED_REASON_NONE;
}
@Override
public boolean isUidRestrictedOnMeteredNetworks(int uid) {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) {
uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
isBackgroundRestricted = mRestrictBackground;
final UidBlockedState uidBlockedState = mUidBlockedState.get(uid);
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) {
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 {
@Override
@@ -5955,6 +5756,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
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
static final class UidBlockedState {
public int blockedReasons;
@@ -6021,6 +5832,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@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(",");
@@ -6101,7 +5917,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
private static String blockedReasonsToString(int blockedReasons) {
public static String blockedReasonsToString(int blockedReasons) {
if (blockedReasons == BLOCKED_REASON_NONE) {
return blockedReasonToString(BLOCKED_REASON_NONE);
}
@@ -6121,7 +5937,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return sb.toString();
}
private static String allowedReasonsToString(int allowedReasons) {
public static String allowedReasonsToString(int allowedReasons) {
if (allowedReasons == ALLOWED_REASON_NONE) {
return allowedReasonToString(ALLOWED_REASON_NONE);
}
@@ -6140,9 +5956,53 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
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 int mId;