wifi data usage: replaced Wi-Fi SSID with a Wi-Fi network key

1. Used SSID to be a wifi network identity can't separate wifi
data usage when there are two different network with same SSID.
Use a new usage key from WifiInfo to replace wifi SSID to solve
this issue.

2. To support to query wifi usage per configured Wifi network.
Adding matchWifiNetworkKeys in NetworkTemplate to support querying
multi networkKeys wifi data usage since each configured Wifi
network configuration might be used to connect different Wifi
network. (Replace mNetworkId with mMatchWifiNetworkKeys)

3. Updated callers who were using NetworkTemplate constructor.

4. Fixed SortedSet null order case. The null subscriberId is a
valid input for matchSubscriberIds.

5. Replaced ArrayUtils with CollectionUtils.

Bug: 197520752
Bug: 126299427
Test: atest -c NetworkTemplateTest
Test: atest -c NetworkStatsServiceTest
Test: atest -c NetworkPolicyManagerServiceTest
Test: atest -c NetworkPolicyTest
Change-Id: Ie20e7fb56597817901be4ce1d2a7afcbc9ded0c6
This commit is contained in:
Les Lee 2021-12-23 11:45:02 +08:00
parent b4ac36e28d
commit 6ca5c25bf4
6 changed files with 158 additions and 98 deletions

View File

@ -369,11 +369,13 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
try {
final NetworkTemplate.Builder builder = new NetworkTemplate.Builder(matchRule)
.setWifiNetworkKey(wifiNetworkKey)
.setMeteredness(metered);
if (subscriberId != null) {
builder.setSubscriberIds(Set.of(subscriberId));
}
if (wifiNetworkKey != null) {
builder.setWifiNetworkKeys(Set.of(wifiNetworkKey));
}
return builder.build();
} catch (IllegalArgumentException e) {
throw new BackupUtils.BadVersionException(
@ -393,7 +395,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
case MATCH_MOBILE:
return !template.getSubscriberIds().isEmpty();
case MATCH_WIFI:
if (Objects.equals(template.getWifiNetworkKey(), null)
if (template.getWifiNetworkKeys().isEmpty()
&& template.getSubscriberIds().isEmpty()) {
return false;
}

View File

@ -32,14 +32,14 @@ import kotlin.test.assertFalse
import kotlin.test.assertTrue
private const val TEST_IMSI1 = "TESTIMSI1"
private const val TEST_SSID1 = "TESTISSID1"
private const val TEST_WIFI_NETWORK_KEY1 = "TESTKEY1"
@RunWith(AndroidJUnit4::class)
class NetworkPolicyTest {
@Test
fun testTemplateBackupRestore() {
assertPolicyBackupRestore(createTestPolicyForTemplate(
NetworkTemplate.buildTemplateWifi(TEST_SSID1)))
NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1)))
assertPolicyBackupRestore(createTestPolicyForTemplate(
NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1)))
assertPolicyBackupRestore(createTestPolicyForTemplate(
@ -79,6 +79,6 @@ class NetworkPolicyTest {
// Verify wifi template can be persistable if the Wifi Network Key is supplied.
assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(MATCH_WIFI)
.setWifiNetworkKey(TEST_SSID1).build()))
.setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1)).build()))
}
}
}

View File

@ -21,7 +21,6 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import android.annotation.Nullable;
import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.service.NetworkIdentityProto;
import android.telephony.Annotation.NetworkType;
import android.util.proto.ProtoOutputStream;
@ -228,11 +227,11 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
if (legacyType == TYPE_WIFI) {
networkId = snapshot.getNetworkCapabilities().getSsid();
if (networkId == null) {
final WifiManager wifi = context.getSystemService(WifiManager.class);
final WifiInfo info = wifi.getConnectionInfo();
networkId = info != null ? info.getSSID() : null;
final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
.getTransportInfo();
if (transportInfo instanceof WifiInfo) {
final WifiInfo info = (WifiInfo) transportInfo;
networkId = info != null ? info.getCurrentNetworkKey() : null;
}
}

View File

@ -35,7 +35,6 @@ import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
import static android.net.wifi.WifiInfo.sanitizeSsid;
import android.annotation.IntDef;
import android.annotation.NonNull;
@ -49,7 +48,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
import com.android.internal.util.ArrayUtils;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkIdentityUtils;
import com.android.net.module.util.NetworkStatsUtils;
@ -57,6 +56,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@ -213,11 +213,14 @@ public final class NetworkTemplate implements Parcelable {
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
@NetworkType int ratType, int metered) {
if (TextUtils.isEmpty(subscriberId)) {
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */,
null /* matchSubscriberIds */,
new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL,
DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId },
new String[0] /* matchWifiNetworkKeys */,
metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
@ -235,7 +238,7 @@ public final class NetworkTemplate implements Parcelable {
/**
* Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
* regardless of SSID.
* regardless of key of the wifi network.
*
* @hide
*/
@ -255,33 +258,40 @@ public final class NetworkTemplate implements Parcelable {
/**
* Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
* given SSID.
* given key of the wifi network.
*
* @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
* to know details about the key.
* @hide
*/
public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
Objects.requireNonNull(networkId);
public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) {
Objects.requireNonNull(wifiNetworkKey);
return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
new String[] { null } /* matchSubscriberIds */,
networkId, METERED_ALL, ROAMING_ALL,
new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL);
}
/**
* Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
* and IMSI.
* Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given
* key of the wifi network and IMSI.
*
* Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code networkId} to get result regardless
* of SSID.
* Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless
* of key of the wifi network.
*
* @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
* to know details about the key.
* @param subscriberId the IMSI associated to this wifi network.
*
* @hide
*/
public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey,
@Nullable String subscriberId) {
return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
networkId, METERED_ALL, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
wifiNetworkKey != null
? new String[] { wifiNetworkKey } : new String[0],
METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
@ -324,7 +334,9 @@ public final class NetworkTemplate implements Parcelable {
public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
Objects.requireNonNull(subscriberId);
return new NetworkTemplate(MATCH_CARRIER, subscriberId,
new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL,
new String[] { subscriberId },
new String[0] /* matchWifiNetworkKeys */,
METERED_YES, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
@ -342,8 +354,8 @@ public final class NetworkTemplate implements Parcelable {
*/
private final String[] mMatchSubscriberIds;
// TODO: Change variable name to match the Api surface.
private final String mNetworkId;
@NonNull
private final String[] mMatchWifiNetworkKeys;
// Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
private final int mMetered;
@ -377,18 +389,19 @@ public final class NetworkTemplate implements Parcelable {
/** @hide */
// TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
@UnsupportedAppUsage
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) {
this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey);
}
/** @hide */
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId) {
String wifiNetworkKey) {
// Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
// to metered networks. It is now possible to match mobile with any meteredness, but
// in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
//constructor passes METERED_YES for these types.
this(matchRule, subscriberId, matchSubscriberIds, networkId,
this(matchRule, subscriberId, matchSubscriberIds,
wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
(matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
: METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
@ -397,23 +410,25 @@ public final class NetworkTemplate implements Parcelable {
/** @hide */
// TODO: Remove it after updating all of the caller.
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId, int metered, int roaming, int defaultNetwork, int subType,
String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int subType,
int oemManaged) {
this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
defaultNetwork, subType, oemManaged,
this(matchRule, subscriberId, matchSubscriberIds,
wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
metered, roaming, defaultNetwork, subType, oemManaged,
NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/** @hide */
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId, int metered, int roaming, int defaultNetwork, int subType,
int oemManaged, int subscriberIdMatchRule) {
String[] matchWifiNetworkKeys, int metered, int roaming,
int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) {
Objects.requireNonNull(matchWifiNetworkKeys);
mMatchRule = matchRule;
mSubscriberId = subscriberId;
// TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
// mSubscriberId is null
mMatchSubscriberIds = matchSubscriberIds;
mNetworkId = networkId;
mMatchWifiNetworkKeys = matchWifiNetworkKeys;
mMetered = metered;
mRoaming = roaming;
mDefaultNetwork = defaultNetwork;
@ -431,7 +446,7 @@ public final class NetworkTemplate implements Parcelable {
mMatchRule = in.readInt();
mSubscriberId = in.readString();
mMatchSubscriberIds = in.createStringArray();
mNetworkId = in.readString();
mMatchWifiNetworkKeys = in.createStringArray();
mMetered = in.readInt();
mRoaming = in.readInt();
mDefaultNetwork = in.readInt();
@ -445,7 +460,7 @@ public final class NetworkTemplate implements Parcelable {
dest.writeInt(mMatchRule);
dest.writeString(mSubscriberId);
dest.writeStringArray(mMatchSubscriberIds);
dest.writeString(mNetworkId);
dest.writeStringArray(mMatchWifiNetworkKeys);
dest.writeInt(mMetered);
dest.writeInt(mRoaming);
dest.writeInt(mDefaultNetwork);
@ -471,9 +486,7 @@ public final class NetworkTemplate implements Parcelable {
builder.append(", matchSubscriberIds=").append(
Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
}
if (mNetworkId != null) {
builder.append(", networkId=").append(mNetworkId);
}
builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys));
if (mMetered != METERED_ALL) {
builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
}
@ -497,8 +510,8 @@ public final class NetworkTemplate implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys),
mMetered, mRoaming, mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
}
@Override
@ -507,13 +520,13 @@ public final class NetworkTemplate implements Parcelable {
final NetworkTemplate other = (NetworkTemplate) obj;
return mMatchRule == other.mMatchRule
&& Objects.equals(mSubscriberId, other.mSubscriberId)
&& Objects.equals(mNetworkId, other.mNetworkId)
&& mMetered == other.mMetered
&& mRoaming == other.mRoaming
&& mDefaultNetwork == other.mDefaultNetwork
&& mSubType == other.mSubType
&& mOemManaged == other.mOemManaged
&& mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
&& mSubscriberIdMatchRule == other.mSubscriberIdMatchRule
&& Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys);
}
return false;
}
@ -579,14 +592,22 @@ public final class NetworkTemplate implements Parcelable {
*/
@Nullable
public String getWifiNetworkKey() {
return mNetworkId;
return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) ? null : mMatchWifiNetworkKeys[0];
}
/**
* Get set of Wifi Network Keys of the template.
*/
@Nullable
public Set<String> getWifiNetworkKeys() {
return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys));
}
/** @hide */
// TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}.
@Nullable
public String getNetworkId() {
return mNetworkId;
return getWifiNetworkKey();
}
/**
@ -703,28 +724,33 @@ public final class NetworkTemplate implements Parcelable {
*/
public boolean matchesSubscriberId(@Nullable String subscriberId) {
return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
|| ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
|| CollectionUtils.contains(mMatchSubscriberIds, subscriberId);
}
/**
* Check if network with matching SSID. Returns true when the SSID matches, or when
* {@code mNetworkId} is {@code WIFI_NETWORK_KEY_ALL}.
* Check if network matches key of the wifi network.
* Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is
* empty.
*
* @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
* to know details about the key.
*/
private boolean matchesWifiNetworkId(@Nullable String networkId) {
return Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL)
|| Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) {
Objects.requireNonNull(wifiNetworkKey);
return CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
|| CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey);
}
/**
* Check if mobile network with matching IMSI.
* Check if mobile network matches IMSI.
*/
private boolean matchesMobile(NetworkIdentity ident) {
if (ident.mType == TYPE_WIMAX) {
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds)
&& CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
}
}
@ -814,7 +840,7 @@ public final class NetworkTemplate implements Parcelable {
switch (ident.mType) {
case TYPE_WIFI:
return matchesSubscriberId(ident.mSubscriberId)
&& matchesWifiNetworkId(ident.mNetworkId);
&& matchesWifiNetworkKey(ident.mNetworkId);
default:
return false;
}
@ -835,8 +861,8 @@ public final class NetworkTemplate implements Parcelable {
*/
private boolean matchesCarrier(NetworkIdentity ident) {
return ident.mSubscriberId != null
&& !ArrayUtils.isEmpty(mMatchSubscriberIds)
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
&& !CollectionUtils.isEmpty(mMatchSubscriberIds)
&& CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
}
private boolean matchesMobileWildcard(NetworkIdentity ident) {
@ -953,11 +979,13 @@ public final class NetworkTemplate implements Parcelable {
if (template.mSubscriberId == null) return template;
for (String[] merged : mergedList) {
if (ArrayUtils.contains(merged, template.mSubscriberId)) {
if (CollectionUtils.contains(merged, template.mSubscriberId)) {
// Requested template subscriber is part of the merge group; return
// a template that matches all merged subscribers.
final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys;
return new NetworkTemplate(template.mMatchRule, merged[0], merged,
template.mNetworkId);
CollectionUtils.isEmpty(matchWifiNetworkKeys)
? null : matchWifiNetworkKeys[0]);
}
}
@ -984,9 +1012,10 @@ public final class NetworkTemplate implements Parcelable {
private final int mMatchRule;
// Use a SortedSet to provide a deterministic order when fetching the first one.
@NonNull
private final SortedSet<String> mMatchSubscriberIds = new TreeSet<>();
@Nullable
private String mWifiNetworkKey;
private final SortedSet<String> mMatchSubscriberIds =
new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder()));
@NonNull
private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>();
// Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
private int mMetered;
@ -1006,7 +1035,6 @@ public final class NetworkTemplate implements Parcelable {
assertRequestableMatchRule(matchRule);
// Initialize members with default values.
mMatchRule = matchRule;
mWifiNetworkKey = WIFI_NETWORK_KEY_ALL;
mMetered = METERED_ALL;
mRoaming = ROAMING_ALL;
mDefaultNetwork = DEFAULT_NETWORK_ALL;
@ -1030,15 +1058,28 @@ public final class NetworkTemplate implements Parcelable {
}
/**
* Set the Wifi Network Key.
* Set the Wifi Network Keys. Calling this function with an empty set represents
* the intention of matching any Wifi Network Key.
*
* @param wifiNetworkKey the Wifi Network Key, see {@link WifiInfo#getCurrentNetworkKey()}.
* Or null to match all networks.
* @param wifiNetworkKeys the list of Wifi Network Key,
* see {@link WifiInfo#getCurrentNetworkKey()}.
* Or an empty list to match all networks.
* Note that {@code getCurrentNetworkKey()} might get null key
* when wifi disconnects. However, the caller should never invoke
* this function with a null Wifi Network Key since such statistics
* never exists.
* @return this builder.
*/
@NonNull
public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) {
mWifiNetworkKey = wifiNetworkKey;
public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) {
Objects.requireNonNull(wifiNetworkKeys);
for (String key : wifiNetworkKeys) {
if (key == null) {
throw new IllegalArgumentException("Null is not a valid key");
}
}
mMatchWifiNetworkKeys.clear();
mMatchWifiNetworkKeys.addAll(wifiNetworkKeys);
return this;
}
@ -1122,9 +1163,17 @@ public final class NetworkTemplate implements Parcelable {
}
private void assertRequestableParameters() {
validateWifiNetworkKeys();
// TODO: Check all the input are legitimate.
}
private void validateWifiNetworkKeys() {
if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) {
throw new IllegalArgumentException("Trying to build non wifi match rule: "
+ mMatchRule + " with wifi network keys");
}
}
/**
* For backward compatibility, deduce match rule to a wildcard match rule
* if the Subscriber Ids are empty.
@ -1133,7 +1182,7 @@ public final class NetworkTemplate implements Parcelable {
if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) {
return MATCH_MOBILE_WILDCARD;
} else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty()
&& mWifiNetworkKey == WIFI_NETWORK_KEY_ALL) {
&& mMatchWifiNetworkKeys.isEmpty()) {
return MATCH_WIFI_WILDCARD;
}
return mMatchRule;
@ -1153,8 +1202,8 @@ public final class NetworkTemplate implements Parcelable {
return new NetworkTemplate(getWildcardDeducedMatchRule(),
mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(),
mMatchSubscriberIds.toArray(new String[0]),
mWifiNetworkKey, mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged,
subscriberIdMatchRule);
mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming,
mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule);
}
}
}

View File

@ -2025,7 +2025,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (final NetworkStateSnapshot snapshot : snapshots) {
mNetIdToSubId.put(snapshot.getNetwork().getNetId(), parseSubId(snapshot));
// Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
// Policies matched by NPMS only match by subscriber ID or by network ID. Thus subtype
// in the object created here is never used and its value doesn't matter, so use
// NETWORK_TYPE_UNKNOWN.
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@ -2455,7 +2455,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
final NetworkTemplate.Builder builder =
new NetworkTemplate.Builder(templateType)
.setWifiNetworkKey(networkId)
.setMeteredness(templateMeteredness);
if (subscriberIdMatchRule
== NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT) {
@ -2463,6 +2462,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
ids.add(subscriberId);
builder.setSubscriberIds(ids);
}
if (networkId != null) {
builder.setWifiNetworkKeys(Set.of(networkId));
}
final NetworkTemplate template = builder.build();
if (NetworkPolicy.isTemplatePersistable(template)) {
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule,
@ -2613,35 +2615,39 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* into {@link WifiConfiguration}.
*/
private void upgradeWifiMeteredOverride() {
final ArrayMap<String, Boolean> wifiNetworkIds = new ArrayMap<>();
final ArrayMap<String, Boolean> wifiNetworkKeys = new ArrayMap<>();
synchronized (mNetworkPoliciesSecondLock) {
for (int i = 0; i < mNetworkPolicy.size();) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
&& !policy.inferred) {
mNetworkPolicy.removeAt(i);
wifiNetworkIds.put(policy.template.getNetworkId(), policy.metered);
final Set<String> keys = policy.template.getWifiNetworkKeys();
wifiNetworkKeys.put(keys.isEmpty() ? null : keys.iterator().next(),
policy.metered);
} else {
i++;
}
}
}
if (wifiNetworkIds.isEmpty()) {
if (wifiNetworkKeys.isEmpty()) {
return;
}
final WifiManager wm = mContext.getSystemService(WifiManager.class);
final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
for (int i = 0; i < configs.size(); ++i) {
final WifiConfiguration config = configs.get(i);
final String networkId = resolveNetworkId(config);
final Boolean metered = wifiNetworkIds.get(networkId);
if (metered != null) {
Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
config.meteredOverride = metered
? WifiConfiguration.METERED_OVERRIDE_METERED
: WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
wm.updateNetwork(config);
for (String key : config.getAllPersistableNetworkKeys()) {
final Boolean metered = wifiNetworkKeys.get(key);
if (metered != null) {
Slog.d(TAG, "Found network " + key + "; upgrading metered hint");
config.meteredOverride = metered
? WifiConfiguration.METERED_OVERRIDE_METERED
: WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
wm.updateNetwork(config);
break;
}
}
}
@ -2683,9 +2689,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
: NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE, subscriberIdMatchRule);
final String networkId = template.getNetworkId();
if (networkId != null) {
out.attribute(null, ATTR_NETWORK_ID, networkId);
if (!template.getWifiNetworkKeys().isEmpty()) {
out.attribute(null, ATTR_NETWORK_ID,
template.getWifiNetworkKeys().iterator().next());
}
writeIntAttribute(out, ATTR_TEMPLATE_METERED,
template.getMeteredness());

View File

@ -129,6 +129,7 @@ import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.INetworkManagementService;
@ -226,13 +227,13 @@ public class NetworkPolicyManagerServiceTest {
private static final long TEST_START = 1194220800000L;
private static final String TEST_IFACE = "test0";
private static final String TEST_SSID = "AndroidAP";
private static final String TEST_WIFI_NETWORK_KEY = "TestWifiNetworkKey";
private static final String TEST_IMSI = "310210";
private static final int TEST_SUB_ID = 42;
private static final Network TEST_NETWORK = mock(Network.class, CALLS_REAL_METHODS);
private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_WIFI_NETWORK_KEY);
private static NetworkTemplate sTemplateCarrierMetered =
buildTemplateCarrierMetered(TEST_IMSI);
@ -2096,10 +2097,13 @@ public class NetworkPolicyManagerServiceTest {
}
private static NetworkStateSnapshot buildWifi() {
WifiInfo mockWifiInfo = mock(WifiInfo.class);
when(mockWifiInfo.makeCopy(anyLong())).thenReturn(mockWifiInfo);
when(mockWifiInfo.getCurrentNetworkKey()).thenReturn(TEST_WIFI_NETWORK_KEY);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities.Builder()
.addTransportType(TRANSPORT_WIFI).setSsid(TEST_SSID).build();
.addTransportType(TRANSPORT_WIFI).setTransportInfo(mockWifiInfo).build();
return new NetworkStateSnapshot(TEST_NETWORK, networkCapabilities, prop,
null /*subscriberId*/, TYPE_WIFI);
}