DO NOT MERGE - Merge ab/7272582
Bug: 190855093
Merged-In: I81c036a8484d14683db9450b55bd379c7a728d73
Change-Id: I71fe9744d88740a8d95235ddb4c8ab91881473ce
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 9f1132b..8a6c85d 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -48,6 +48,7 @@
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.DataUnit;
import android.util.Log;
@@ -214,6 +215,10 @@
* null} value when querying for the mobile network type to receive usage
* for all mobile networks. For additional details see {@link
* TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
* @param startTime Start of period. Defined in terms of "Unix time", see
* {@link java.lang.System#currentTimeMillis}.
* @param endTime End of period. Defined in terms of "Unix time", see
@@ -255,6 +260,10 @@
* null} value when querying for the mobile network type to receive usage
* for all mobile networks. For additional details see {@link
* TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
* @param startTime Start of period. Defined in terms of "Unix time", see
* {@link java.lang.System#currentTimeMillis}.
* @param endTime End of period. Defined in terms of "Unix time", see
@@ -300,6 +309,10 @@
* null} value when querying for the mobile network type to receive usage
* for all mobile networks. For additional details see {@link
* TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
* @param startTime Start of period. Defined in terms of "Unix time", see
* {@link java.lang.System#currentTimeMillis}.
* @param endTime End of period. Defined in terms of "Unix time", see
@@ -388,6 +401,10 @@
* null} value when querying for the mobile network type to receive usage
* for all mobile networks. For additional details see {@link
* TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
* @param startTime Start of period. Defined in terms of "Unix time", see
* {@link java.lang.System#currentTimeMillis}.
* @param endTime End of period. Defined in terms of "Unix time", see
@@ -450,6 +467,10 @@
* null} value when querying for the mobile network type to receive usage
* for all mobile networks. For additional details see {@link
* TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
* @param startTime Start of period. Defined in terms of "Unix time", see
* {@link java.lang.System#currentTimeMillis}.
* @param endTime End of period. Defined in terms of "Unix time", see
@@ -531,6 +552,10 @@
* null} value when registering for the mobile network type to receive
* notifications for all mobile networks. For additional details see {@link
* TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
* @param thresholdBytes Threshold in bytes to be notified on.
* @param callback The {@link UsageCallback} that the system will call when data usage
* has exceeded the specified threshold.
@@ -644,7 +669,10 @@
: NetworkTemplate.buildTemplateMobileAll(subscriberId);
break;
case ConnectivityManager.TYPE_WIFI:
- template = NetworkTemplate.buildTemplateWifiWildcard();
+ template = TextUtils.isEmpty(subscriberId)
+ ? NetworkTemplate.buildTemplateWifiWildcard()
+ : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
+ subscriberId);
break;
default:
throw new IllegalArgumentException("Cannot create template for network type "
@@ -655,14 +683,14 @@
}
/**
- * Notify {@code NetworkStatsService} about network status changed.
+ * Notify {@code NetworkStatsService} about network status changed.
*
- * Notifies NetworkStatsService of network state changes for data usage accounting purposes.
+ * Notifies NetworkStatsService of network state changes for data usage accounting purposes.
*
- * To avoid races that attribute data usage to wrong network, such as new network with
- * the same interface after SIM hot-swap, this function will not return until
- * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
- * all data sources.
+ * To avoid races that attribute data usage to wrong network, such as new network with
+ * the same interface after SIM hot-swap, this function will not return until
+ * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from
+ * all data sources.
*
* @param defaultNetworks the list of all networks that could be used by network traffic that
* does not explicitly select a network.
@@ -689,8 +717,7 @@
Objects.requireNonNull(defaultNetworks);
Objects.requireNonNull(networkStateSnapshots);
Objects.requireNonNull(underlyingNetworkInfos);
- // TODO: Change internal namings after the name is decided.
- mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]),
+ mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]),
networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface,
underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0]));
} catch (RemoteException e) {
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index dc3b88a..12937b5 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -65,8 +65,8 @@
/** Increment data layer count of operations performed for UID and tag. */
void incrementOperationCount(int uid, int tag, int operationCount);
- /** Force update of ifaces. */
- void forceUpdateIfaces(
+ /** Notify {@code NetworkStatsService} about network status changed. */
+ void notifyNetworkStatus(
in Network[] defaultNetworks,
in NetworkStateSnapshot[] snapshots,
in String activeIface,
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 98acd98..c106807 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -79,6 +79,16 @@
public static final int DIRECTION_OUT = 1;
/**
+ * Used when applying a transform to direct traffic through an {@link IpSecTransform} for
+ * forwarding between interfaces.
+ *
+ * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
+ *
+ * @hide
+ */
+ public static final int DIRECTION_FWD = 2;
+
+ /**
* The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
*
* <p>No IPsec packet may contain an SPI of 0.
@@ -800,7 +810,9 @@
*
* @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
* This network MUST never be the network exposing this IpSecTunnelInterface, otherwise
- * this method will throw an {@link IllegalArgumentException}.
+ * this method will throw an {@link IllegalArgumentException}. If the
+ * IpSecTunnelInterface is later added to this network, all outbound traffic will be
+ * blackholed.
*/
// TODO: b/169171001 Update the documentation when transform migration is supported.
// The purpose of making updating network and applying transforms separate is to leave open
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 1eef7d9..1d07a03 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -26,8 +26,10 @@
import android.telephony.Annotation.NetworkType;
import android.util.proto.ProtoOutputStream;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.net.module.util.NetworkIdentityUtils;
+import java.util.ArrayList;
import java.util.Objects;
/**
@@ -121,11 +123,37 @@
}
builder.append(", metered=").append(mMetered);
builder.append(", defaultNetwork=").append(mDefaultNetwork);
- // TODO(180557699): Print a human readable string for OEM managed state.
- builder.append(", oemManaged=").append(mOemManaged);
+ builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
return builder.append("}").toString();
}
+ /**
+ * Get the human readable representation of a bitfield representing the OEM managed state of a
+ * network.
+ */
+ static String getOemManagedNames(int oemManaged) {
+ if (oemManaged == OEM_NONE) {
+ return "OEM_NONE";
+ }
+ final int[] bitPositions = NetworkCapabilitiesUtils.unpackBits(oemManaged);
+ final ArrayList<String> oemManagedNames = new ArrayList<String>();
+ for (int position : bitPositions) {
+ oemManagedNames.add(nameOfOemManaged(1 << position));
+ }
+ return String.join(",", oemManagedNames);
+ }
+
+ private static String nameOfOemManaged(int oemManagedBit) {
+ switch (oemManagedBit) {
+ case OEM_PAID:
+ return "OEM_PAID";
+ case OEM_PRIVATE:
+ return "OEM_PRIVATE";
+ default:
+ return "Invalid(" + oemManagedBit + ")";
+ }
+ }
+
public void dumpDebug(ProtoOutputStream proto, long tag) {
final long start = proto.start(tag);
@@ -186,19 +214,19 @@
*/
public static NetworkIdentity buildNetworkIdentity(Context context,
NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) {
- final int legacyType = snapshot.legacyType;
+ final int legacyType = snapshot.getLegacyType();
- final String subscriberId = snapshot.subscriberId;
+ final String subscriberId = snapshot.getSubscriberId();
String networkId = null;
- boolean roaming = !snapshot.networkCapabilities.hasCapability(
+ boolean roaming = !snapshot.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- boolean metered = !snapshot.networkCapabilities.hasCapability(
+ boolean metered = !snapshot.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- final int oemManaged = getOemBitfield(snapshot.networkCapabilities);
+ final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
if (legacyType == TYPE_WIFI) {
- networkId = snapshot.networkCapabilities.getSsid();
+ networkId = snapshot.getNetworkCapabilities().getSsid();
if (networkId == null) {
final WifiManager wifi = context.getSystemService(WifiManager.class);
final WifiInfo info = wifi.getConnectionInfo();
diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java
index 0d26c2d..9df861a 100644
--- a/core/java/android/net/NetworkStateSnapshot.java
+++ b/core/java/android/net/NetworkStateSnapshot.java
@@ -37,47 +37,76 @@
public final class NetworkStateSnapshot implements Parcelable {
/** The network associated with this snapshot. */
@NonNull
- public final Network network;
+ private final Network mNetwork;
/** The {@link NetworkCapabilities} of the network associated with this snapshot. */
@NonNull
- public final NetworkCapabilities networkCapabilities;
+ private final NetworkCapabilities mNetworkCapabilities;
/** The {@link LinkProperties} of the network associated with this snapshot. */
@NonNull
- public final LinkProperties linkProperties;
+ private final LinkProperties mLinkProperties;
/**
* The Subscriber Id of the network associated with this snapshot. See
* {@link android.telephony.TelephonyManager#getSubscriberId()}.
*/
@Nullable
- public final String subscriberId;
+ private final String mSubscriberId;
/**
* The legacy type of the network associated with this snapshot. See
* {@code ConnectivityManager#TYPE_*}.
*/
- public final int legacyType;
+ private final int mLegacyType;
public NetworkStateSnapshot(@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull LinkProperties linkProperties,
@Nullable String subscriberId, int legacyType) {
- this.network = Objects.requireNonNull(network);
- this.networkCapabilities = Objects.requireNonNull(networkCapabilities);
- this.linkProperties = Objects.requireNonNull(linkProperties);
- this.subscriberId = subscriberId;
- this.legacyType = legacyType;
+ mNetwork = Objects.requireNonNull(network);
+ mNetworkCapabilities = Objects.requireNonNull(networkCapabilities);
+ mLinkProperties = Objects.requireNonNull(linkProperties);
+ mSubscriberId = subscriberId;
+ mLegacyType = legacyType;
}
/** @hide */
public NetworkStateSnapshot(@NonNull Parcel in) {
- network = in.readParcelable(null);
- networkCapabilities = in.readParcelable(null);
- linkProperties = in.readParcelable(null);
- subscriberId = in.readString();
- legacyType = in.readInt();
+ mNetwork = in.readParcelable(null);
+ mNetworkCapabilities = in.readParcelable(null);
+ mLinkProperties = in.readParcelable(null);
+ mSubscriberId = in.readString();
+ mLegacyType = in.readInt();
+ }
+
+ /** Get the network associated with this snapshot */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /** Get {@link NetworkCapabilities} of the network associated with this snapshot. */
+ @NonNull
+ public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
+
+ /** Get the {@link LinkProperties} of the network associated with this snapshot. */
+ @NonNull
+ public LinkProperties getLinkProperties() {
+ return mLinkProperties;
+ }
+
+ /** Get the Subscriber Id of the network associated with this snapshot. */
+ @Nullable
+ public String getSubscriberId() {
+ return mSubscriberId;
+ }
+
+ /** Get the legacy type of the network associated with this snapshot. */
+ public int getLegacyType() {
+ return mLegacyType;
}
@Override
@@ -87,11 +116,11 @@
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeParcelable(network, flags);
- out.writeParcelable(networkCapabilities, flags);
- out.writeParcelable(linkProperties, flags);
- out.writeString(subscriberId);
- out.writeInt(legacyType);
+ out.writeParcelable(mNetwork, flags);
+ out.writeParcelable(mNetworkCapabilities, flags);
+ out.writeParcelable(mLinkProperties, flags);
+ out.writeString(mSubscriberId);
+ out.writeInt(mLegacyType);
}
@NonNull
@@ -115,26 +144,27 @@
if (this == o) return true;
if (!(o instanceof NetworkStateSnapshot)) return false;
NetworkStateSnapshot that = (NetworkStateSnapshot) o;
- return legacyType == that.legacyType
- && Objects.equals(network, that.network)
- && Objects.equals(networkCapabilities, that.networkCapabilities)
- && Objects.equals(linkProperties, that.linkProperties)
- && Objects.equals(subscriberId, that.subscriberId);
+ return mLegacyType == that.mLegacyType
+ && Objects.equals(mNetwork, that.mNetwork)
+ && Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities)
+ && Objects.equals(mLinkProperties, that.mLinkProperties)
+ && Objects.equals(mSubscriberId, that.mSubscriberId);
}
@Override
public int hashCode() {
- return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType);
+ return Objects.hash(mNetwork,
+ mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType);
}
@Override
public String toString() {
return "NetworkStateSnapshot{"
- + "network=" + network
- + ", networkCapabilities=" + networkCapabilities
- + ", linkProperties=" + linkProperties
- + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + '\''
- + ", legacyType=" + legacyType
+ + "network=" + mNetwork
+ + ", networkCapabilities=" + mNetworkCapabilities
+ + ", linkProperties=" + mLinkProperties
+ + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\''
+ + ", legacyType=" + mLegacyType
+ '}';
}
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index d42beae..6ccbab7 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -38,6 +38,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
@@ -1423,11 +1424,11 @@
* @hide
*/
public void migrateTun(int tunUid, @NonNull String tunIface,
- @NonNull String[] underlyingIfaces) {
+ @NonNull List<String> underlyingIfaces) {
// Combined usage by all apps using VPN.
final Entry tunIfaceTotal = new Entry();
// Usage by VPN, grouped by its {@code underlyingIfaces}.
- final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length];
+ final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.size()];
// Usage by VPN, summed across all its {@code underlyingIfaces}.
final Entry underlyingIfacesTotal = new Entry();
@@ -1468,7 +1469,7 @@
* {@code underlyingIfaces}
*/
private void tunAdjustmentInit(int tunUid, @NonNull String tunIface,
- @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal,
+ @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal,
@NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) {
final Entry recycle = new Entry();
for (int i = 0; i < size; i++) {
@@ -1488,8 +1489,8 @@
if (recycle.uid == tunUid) {
// Add up traffic through tunUid's underlying interfaces.
- for (int j = 0; j < underlyingIfaces.length; j++) {
- if (Objects.equals(underlyingIfaces[j], recycle.iface)) {
+ for (int j = 0; j < underlyingIfaces.size(); j++) {
+ if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) {
perInterfaceTotal[j].add(recycle);
underlyingIfacesTotal.add(recycle);
break;
@@ -1515,12 +1516,12 @@
* underlyingIfaces}
*/
private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface,
- @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal,
+ @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal,
@NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) {
// Traffic that should be moved off of each underlying interface for tunUid (see
// deductTrafficFromVpnApp below).
- final Entry[] moved = new Entry[underlyingIfaces.length];
- for (int i = 0; i < underlyingIfaces.length; i++) {
+ final Entry[] moved = new Entry[underlyingIfaces.size()];
+ for (int i = 0; i < underlyingIfaces.size(); i++) {
moved[i] = new Entry();
}
@@ -1582,8 +1583,8 @@
}
// In a second pass, distribute these values across interfaces in the proportion that
// each interface represents of the total traffic of the underlying interfaces.
- for (int j = 0; j < underlyingIfaces.length; j++) {
- tmpEntry.iface = underlyingIfaces[j];
+ for (int j = 0; j < underlyingIfaces.size(); j++) {
+ tmpEntry.iface = underlyingIfaces.get(j);
tmpEntry.rxBytes = 0;
// Reset 'set' to correct value since it gets updated when adding debug info below.
tmpEntry.set = set[i];
@@ -1638,14 +1639,14 @@
private void deductTrafficFromVpnApp(
int tunUid,
- @NonNull String[] underlyingIfaces,
+ @NonNull List<String> underlyingIfaces,
@NonNull Entry[] moved) {
- for (int i = 0; i < underlyingIfaces.length; i++) {
+ for (int i = 0; i < underlyingIfaces.size(); i++) {
moved[i].uid = tunUid;
// Add debug info
moved[i].set = SET_DBG_VPN_OUT;
moved[i].tag = TAG_NONE;
- moved[i].iface = underlyingIfaces[i];
+ moved[i].iface = underlyingIfaces.get(i);
moved[i].metered = METERED_ALL;
moved[i].roaming = ROAMING_ALL;
moved[i].defaultNetwork = DEFAULT_NETWORK_ALL;
@@ -1658,7 +1659,7 @@
// METERED_NO, which should be the case as it comes directly from the /proc file.
// We only blend in the roaming data after applying these adjustments, by checking the
// NetworkIdentity of the underlying iface.
- final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT,
+ final int idxVpnBackground = findIndex(underlyingIfaces.get(i), tunUid, SET_DEFAULT,
TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
if (idxVpnBackground != -1) {
// Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed
@@ -1666,7 +1667,7 @@
tunSubtract(idxVpnBackground, this, moved[i]);
}
- final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND,
+ final int idxVpnForeground = findIndex(underlyingIfaces.get(i), tunUid, SET_FOREGROUND,
TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
if (idxVpnForeground != -1) {
tunSubtract(idxVpnForeground, this, moved[i]);
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index c83dd99..68917a8 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -82,6 +82,24 @@
public static final int MATCH_WIFI_WILDCARD = 7;
public static final int MATCH_BLUETOOTH = 8;
public static final int MATCH_PROXY = 9;
+ public static final int MATCH_CARRIER = 10;
+
+ /**
+ * Value of the match rule of the subscriberId to match networks with specific subscriberId.
+ */
+ public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0;
+ /**
+ * Value of the match rule of the subscriberId to match networks with any subscriberId which
+ * includes null and non-null.
+ */
+ public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1;
+
+ /**
+ * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that
+ * should be fixed), so it's not possible to want to match null vs
+ * non-null. Therefore it's fine to use null as a sentinel for Network ID.
+ */
+ public static final String WIFI_NETWORKID_ALL = null;
/**
* Include all network types when filtering. This is meant to merge in with the
@@ -125,6 +143,7 @@
case MATCH_WIFI_WILDCARD:
case MATCH_BLUETOOTH:
case MATCH_PROXY:
+ case MATCH_CARRIER:
return true;
default:
@@ -168,10 +187,12 @@
@NetworkType int ratType) {
if (TextUtils.isEmpty(subscriberId)) {
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL);
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -189,6 +210,8 @@
*/
@UnsupportedAppUsage
public static NetworkTemplate buildTemplateWifiWildcard() {
+ // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL
+ // and SUBSCRIBER_ID_MATCH_RULE_ALL.
return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
}
@@ -202,8 +225,27 @@
* Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
* given SSID.
*/
- public static NetworkTemplate buildTemplateWifi(String networkId) {
- return new NetworkTemplate(MATCH_WIFI, null, networkId);
+ public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
+ Objects.requireNonNull(networkId);
+ return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
+ new String[] { null } /* matchSubscriberIds */,
+ networkId, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_ALL);
+ }
+
+ /**
+ * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
+ * and IMSI.
+ *
+ * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID.
+ */
+ public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
+ @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,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -231,6 +273,17 @@
return new NetworkTemplate(MATCH_PROXY, null, null);
}
+ /**
+ * Template to match all metered carrier networks with the given IMSI.
+ */
+ 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,
+ DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ }
+
private final int mMatchRule;
private final String mSubscriberId;
@@ -251,10 +304,26 @@
private final int mRoaming;
private final int mDefaultNetwork;
private final int mSubType;
+ private final int mSubscriberIdMatchRule;
// Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
private final int mOemManaged;
+ private void checkValidSubscriberIdMatchRule() {
+ switch (mMatchRule) {
+ case MATCH_MOBILE:
+ case MATCH_CARRIER:
+ // MOBILE and CARRIER templates must always specify a subscriber ID.
+ if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
+ throw new IllegalArgumentException("Invalid SubscriberIdMatchRule"
+ + "on match rule: " + getMatchRuleName(mMatchRule));
+ }
+ return;
+ default:
+ return;
+ }
+ }
+
@UnsupportedAppUsage
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
@@ -263,14 +332,25 @@
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId) {
this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
+ DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ }
+
+ // 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,
+ int oemManaged) {
+ this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
+ defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId, int metered, int roaming, int defaultNetwork, int subType,
- int oemManaged) {
+ int oemManaged, int subscriberIdMatchRule) {
mMatchRule = matchRule;
mSubscriberId = subscriberId;
+ // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
+ // mSubscriberId is null
mMatchSubscriberIds = matchSubscriberIds;
mNetworkId = networkId;
mMetered = metered;
@@ -278,7 +358,8 @@
mDefaultNetwork = defaultNetwork;
mSubType = subType;
mOemManaged = oemManaged;
-
+ mSubscriberIdMatchRule = subscriberIdMatchRule;
+ checkValidSubscriberIdMatchRule();
if (!isKnownMatchRule(matchRule)) {
Log.e(TAG, "Unknown network template rule " + matchRule
+ " will not match any identity.");
@@ -295,6 +376,7 @@
mDefaultNetwork = in.readInt();
mSubType = in.readInt();
mOemManaged = in.readInt();
+ mSubscriberIdMatchRule = in.readInt();
}
@Override
@@ -308,6 +390,7 @@
dest.writeInt(mDefaultNetwork);
dest.writeInt(mSubType);
dest.writeInt(mOemManaged);
+ dest.writeInt(mSubscriberIdMatchRule);
}
@Override
@@ -344,15 +427,17 @@
builder.append(", subType=").append(mSubType);
}
if (mOemManaged != OEM_MANAGED_ALL) {
- builder.append(", oemManaged=").append(mOemManaged);
+ builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged));
}
+ builder.append(", subscriberIdMatchRule=")
+ .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule));
return builder.toString();
}
@Override
public int hashCode() {
return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
- mDefaultNetwork, mSubType, mOemManaged);
+ mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
}
@Override
@@ -366,11 +451,23 @@
&& mRoaming == other.mRoaming
&& mDefaultNetwork == other.mDefaultNetwork
&& mSubType == other.mSubType
- && mOemManaged == other.mOemManaged;
+ && mOemManaged == other.mOemManaged
+ && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
}
return false;
}
+ private String subscriberIdMatchRuleToString(int rule) {
+ switch (rule) {
+ case SUBSCRIBER_ID_MATCH_RULE_EXACT:
+ return "EXACT_MATCH";
+ case SUBSCRIBER_ID_MATCH_RULE_ALL:
+ return "ALL";
+ default:
+ return "Unknown rule " + rule;
+ }
+ }
+
public boolean isMatchRuleMobile() {
switch (mMatchRule) {
case MATCH_MOBILE:
@@ -386,6 +483,14 @@
case MATCH_MOBILE_WILDCARD:
case MATCH_WIFI_WILDCARD:
return false;
+ case MATCH_CARRIER:
+ return mSubscriberId != null;
+ case MATCH_WIFI:
+ if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
+ && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
+ return false;
+ }
+ return true;
default:
return true;
}
@@ -405,6 +510,14 @@
return mNetworkId;
}
+ public int getSubscriberIdMatchRule() {
+ return mSubscriberIdMatchRule;
+ }
+
+ public int getMeteredness() {
+ return mMetered;
+ }
+
/**
* Test if given {@link NetworkIdentity} matches this template.
*/
@@ -429,6 +542,8 @@
return matchesBluetooth(ident);
case MATCH_PROXY:
return matchesProxy(ident);
+ case MATCH_CARRIER:
+ return matchesCarrier(ident);
default:
// We have no idea what kind of network template we are, so we
// just claim not to match anything.
@@ -466,8 +581,23 @@
|| getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
}
- public boolean matchesSubscriberId(String subscriberId) {
- return ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+ /**
+ * Check if this template matches {@code subscriberId}. Returns true if this
+ * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a
+ * {@code mMatchSubscriberIds} array that contains {@code subscriberId}.
+ */
+ public boolean matchesSubscriberId(@Nullable String subscriberId) {
+ return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL
+ || ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+ }
+
+ /**
+ * Check if network with matching SSID. Returns true when the SSID matches, or when
+ * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}.
+ */
+ private boolean matchesWifiNetworkId(@Nullable String networkId) {
+ return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
+ || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
}
/**
@@ -566,8 +696,8 @@
private boolean matchesWifi(NetworkIdentity ident) {
switch (ident.mType) {
case TYPE_WIFI:
- return Objects.equals(
- sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId));
+ return matchesSubscriberId(ident.mSubscriberId)
+ && matchesWifiNetworkId(ident.mNetworkId);
default:
return false;
}
@@ -583,6 +713,15 @@
return false;
}
+ /**
+ * Check if matches carrier network. The carrier networks means it includes the subscriberId.
+ */
+ private boolean matchesCarrier(NetworkIdentity ident) {
+ return ident.mSubscriberId != null
+ && !ArrayUtils.isEmpty(mMatchSubscriberIds)
+ && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
+ }
+
private boolean matchesMobileWildcard(NetworkIdentity ident) {
if (ident.mType == TYPE_WIMAX) {
return true;
@@ -635,11 +774,26 @@
return "BLUETOOTH";
case MATCH_PROXY:
return "PROXY";
+ case MATCH_CARRIER:
+ return "CARRIER";
default:
return "UNKNOWN(" + matchRule + ")";
}
}
+ private static String getOemManagedNames(int oemManaged) {
+ switch (oemManaged) {
+ case OEM_MANAGED_ALL:
+ return "OEM_MANAGED_ALL";
+ case OEM_MANAGED_NO:
+ return "OEM_MANAGED_NO";
+ case OEM_MANAGED_YES:
+ return "OEM_MANAGED_YES";
+ default:
+ return NetworkIdentity.getOemManagedNames(oemManaged);
+ }
+ }
+
/**
* Examine the given template and normalize if it refers to a "merged"
* mobile subscriber. We pick the "lowest" merged subscriber as the primary
diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java
index 7bf9231..33f9375 100644
--- a/core/java/android/net/UnderlyingNetworkInfo.java
+++ b/core/java/android/net/UnderlyingNetworkInfo.java
@@ -37,36 +37,56 @@
@SystemApi(client = MODULE_LIBRARIES)
public final class UnderlyingNetworkInfo implements Parcelable {
/** The owner of this network. */
- public final int ownerUid;
+ private final int mOwnerUid;
+
/** The interface name of this network. */
@NonNull
- public final String iface;
+ private final String mIface;
+
/** The names of the interfaces underlying this network. */
@NonNull
- public final List<String> underlyingIfaces;
+ private final List<String> mUnderlyingIfaces;
public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface,
@NonNull List<String> underlyingIfaces) {
Objects.requireNonNull(iface);
Objects.requireNonNull(underlyingIfaces);
- this.ownerUid = ownerUid;
- this.iface = iface;
- this.underlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces));
+ mOwnerUid = ownerUid;
+ mIface = iface;
+ mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces));
}
private UnderlyingNetworkInfo(@NonNull Parcel in) {
- this.ownerUid = in.readInt();
- this.iface = in.readString();
- this.underlyingIfaces = new ArrayList<>();
- in.readList(this.underlyingIfaces, null /*classLoader*/);
+ mOwnerUid = in.readInt();
+ mIface = in.readString();
+ List<String> underlyingIfaces = new ArrayList<>();
+ in.readList(underlyingIfaces, null /*classLoader*/);
+ mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces);
+ }
+
+ /** Get the owner of this network. */
+ public int getOwnerUid() {
+ return mOwnerUid;
+ }
+
+ /** Get the interface name of this network. */
+ @NonNull
+ public String getInterface() {
+ return mIface;
+ }
+
+ /** Get the names of the interfaces underlying this network. */
+ @NonNull
+ public List<String> getUnderlyingInterfaces() {
+ return mUnderlyingIfaces;
}
@Override
public String toString() {
return "UnderlyingNetworkInfo{"
- + "ownerUid=" + ownerUid
- + ", iface='" + iface + '\''
- + ", underlyingIfaces='" + underlyingIfaces.toString() + '\''
+ + "ownerUid=" + mOwnerUid
+ + ", iface='" + mIface + '\''
+ + ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\''
+ '}';
}
@@ -77,9 +97,9 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(ownerUid);
- dest.writeString(iface);
- dest.writeList(underlyingIfaces);
+ dest.writeInt(mOwnerUid);
+ dest.writeString(mIface);
+ dest.writeList(mUnderlyingIfaces);
}
@NonNull
@@ -103,13 +123,13 @@
if (this == o) return true;
if (!(o instanceof UnderlyingNetworkInfo)) return false;
final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o;
- return ownerUid == that.ownerUid
- && Objects.equals(iface, that.iface)
- && Objects.equals(underlyingIfaces, that.underlyingIfaces);
+ return mOwnerUid == that.getOwnerUid()
+ && Objects.equals(mIface, that.getInterface())
+ && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces());
}
@Override
public int hashCode() {
- return Objects.hash(ownerUid, iface, underlyingIfaces);
+ return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces);
}
}
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 64f20b8..5a25cfc 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -200,6 +200,9 @@
public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20;
/** @hide */
+ public static final int DAEMON_CLEANUP = BASE + 21;
+
+ /** @hide */
public static final int ENABLE = BASE + 24;
/** @hide */
public static final int DISABLE = BASE + 25;
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 794cb93..d6ee951 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -49,6 +49,7 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.system.ErrnoException;
@@ -65,6 +66,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.net.module.util.NetdUtils;
+import com.android.net.module.util.PermissionUtils;
import libcore.io.IoUtils;
@@ -466,8 +468,7 @@
/** Safety method; guards against access of other user's UserRecords */
private void checkCallerUid(int uid) {
- if (uid != Binder.getCallingUid()
- && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
+ if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) {
throw new SecurityException("Attempted access of unowned resources");
}
}
@@ -1105,11 +1106,15 @@
* Checks the user-provided direction field and throws an IllegalArgumentException if it is not
* DIRECTION_IN or DIRECTION_OUT
*/
- private static void checkDirection(int direction) {
+ private void checkDirection(int direction) {
switch (direction) {
case IpSecManager.DIRECTION_OUT:
case IpSecManager.DIRECTION_IN:
return;
+ case IpSecManager.DIRECTION_FWD:
+ // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ return;
}
throw new IllegalArgumentException("Invalid Direction: " + direction);
}
@@ -1353,6 +1358,26 @@
ikey,
0xffffffff,
resourceId);
+
+ // Add a forwarding policy on the tunnel interface. In order to support forwarding
+ // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA.
+ //
+ // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD,
+ // forwarding will be blocked by default (as would be the case if this policy was
+ // absent).
+ //
+ // This is necessary only on the tunnel interface, and not any the interface to
+ // which traffic will be forwarded to.
+ netd.ipSecAddSecurityPolicy(
+ callerUid,
+ selAddrFamily,
+ IpSecManager.DIRECTION_FWD,
+ remoteAddr,
+ localAddr,
+ 0,
+ ikey,
+ 0xffffffff,
+ resourceId);
}
userRecord.mTunnelInterfaceRecords.put(
@@ -1820,7 +1845,7 @@
int mark =
(direction == IpSecManager.DIRECTION_OUT)
? tunnelInterfaceInfo.getOkey()
- : tunnelInterfaceInfo.getIkey();
+ : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies
try {
// Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index d907505..38f7cf6 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -61,6 +61,7 @@
private static final String MDNS_TAG = "mDnsConnector";
private static final boolean DBG = true;
+ private static final long CLEANUP_DELAY_MS = 3000;
private final Context mContext;
private final NsdSettings mNsdSettings;
@@ -77,6 +78,7 @@
private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>();
private final AsyncChannel mReplyChannel = new AsyncChannel();
+ private final long mCleanupDelayMs;
private static final int INVALID_ID = 0;
private int mUniqueId = 1;
@@ -92,6 +94,22 @@
return NsdManager.nameOf(what);
}
+ void maybeStartDaemon() {
+ mDaemon.maybeStart();
+ maybeScheduleStop();
+ }
+
+ void maybeScheduleStop() {
+ if (!isAnyRequestActive()) {
+ cancelStop();
+ sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
+ }
+ }
+
+ void cancelStop() {
+ this.removeMessages(NsdManager.DAEMON_CLEANUP);
+ }
+
/**
* Observes the NSD on/off setting, and takes action when changed.
*/
@@ -151,10 +169,6 @@
cInfo.expungeAllRequests();
mClients.remove(msg.replyTo);
}
- //Last client
- if (mClients.size() == 0) {
- mDaemon.stop();
- }
break;
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
AsyncChannel ac = new AsyncChannel();
@@ -180,6 +194,9 @@
replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
NsdManager.FAILURE_INTERNAL_ERROR);
break;
+ case NsdManager.DAEMON_CLEANUP:
+ mDaemon.maybeStop();
+ break;
case NsdManager.NATIVE_DAEMON_EVENT:
default:
Slog.e(TAG, "Unhandled " + msg);
@@ -212,16 +229,13 @@
@Override
public void enter() {
sendNsdStateChangeBroadcast(true);
- if (mClients.size() > 0) {
- mDaemon.start();
- }
}
@Override
public void exit() {
- if (mClients.size() > 0) {
- mDaemon.stop();
- }
+ // TODO: it is incorrect to stop the daemon without expunging all requests
+ // and sending error callbacks to clients.
+ maybeScheduleStop();
}
private boolean requestLimitReached(ClientInfo clientInfo) {
@@ -236,12 +250,15 @@
clientInfo.mClientIds.put(clientId, globalId);
clientInfo.mClientRequests.put(clientId, what);
mIdToClientInfoMap.put(globalId, clientInfo);
+ // Remove the cleanup event because here comes a new request.
+ cancelStop();
}
private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
clientInfo.mClientIds.delete(clientId);
clientInfo.mClientRequests.delete(clientId);
mIdToClientInfoMap.remove(globalId);
+ maybeScheduleStop();
}
@Override
@@ -251,14 +268,12 @@
int id;
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- //First client
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
- mClients.size() == 0) {
- mDaemon.start();
- }
return NOT_HANDLED;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
return NOT_HANDLED;
+ }
+
+ switch (msg.what) {
case NsdManager.DISABLE:
//TODO: cleanup clients
transitionTo(mDisabledState);
@@ -274,6 +289,7 @@
break;
}
+ maybeStartDaemon();
id = getUniqueId();
if (discoverServices(id, servInfo.getServiceType())) {
if (DBG) {
@@ -316,6 +332,7 @@
break;
}
+ maybeStartDaemon();
id = getUniqueId();
if (registerService(id, (NsdServiceInfo) msg.obj)) {
if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
@@ -357,6 +374,7 @@
break;
}
+ maybeStartDaemon();
id = getUniqueId();
if (resolveService(id, servInfo)) {
clientInfo.mResolvedService = new NsdServiceInfo();
@@ -513,6 +531,10 @@
}
}
+ private boolean isAnyRequestActive() {
+ return mIdToClientInfoMap.size() != 0;
+ }
+
private String unescape(String s) {
StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); ++i) {
@@ -538,7 +560,9 @@
}
@VisibleForTesting
- NsdService(Context ctx, NsdSettings settings, Handler handler, DaemonConnectionSupplier fn) {
+ NsdService(Context ctx, NsdSettings settings, Handler handler,
+ DaemonConnectionSupplier fn, long cleanupDelayMs) {
+ mCleanupDelayMs = cleanupDelayMs;
mContext = ctx;
mNsdSettings = settings;
mNsdStateMachine = new NsdStateMachine(TAG, handler);
@@ -552,7 +576,8 @@
HandlerThread thread = new HandlerThread(TAG);
thread.start();
Handler handler = new Handler(thread.getLooper());
- NsdService service = new NsdService(context, settings, handler, DaemonConnection::new);
+ NsdService service = new NsdService(context, settings, handler,
+ DaemonConnection::new, CLEANUP_DELAY_MS);
service.mDaemonCallback.awaitConnection();
return service;
}
@@ -681,12 +706,16 @@
@VisibleForTesting
public static class DaemonConnection {
final NativeDaemonConnector mNativeConnector;
+ boolean mIsStarted = false;
DaemonConnection(NativeCallbackReceiver callback) {
mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null);
new Thread(mNativeConnector, MDNS_TAG).start();
}
+ /**
+ * Executes the specified cmd on the daemon.
+ */
public boolean execute(Object... args) {
if (DBG) {
Slog.d(TAG, "mdnssd " + Arrays.toString(args));
@@ -700,12 +729,26 @@
return true;
}
- public void start() {
+ /**
+ * Starts the daemon if it is not already started.
+ */
+ public void maybeStart() {
+ if (mIsStarted) {
+ return;
+ }
execute("start-service");
+ mIsStarted = true;
}
- public void stop() {
+ /**
+ * Stops the daemon if it is started.
+ */
+ public void maybeStop() {
+ if (!mIsStarted) {
+ return;
+ }
execute("stop-service");
+ mIsStarted = false;
}
}
@@ -864,6 +907,7 @@
}
mClientIds.clear();
mClientRequests.clear();
+ mNsdStateMachine.maybeScheduleStop();
}
// mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id,
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index d042b88..431b009 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -382,8 +382,8 @@
// Migrate data usage over a VPN to the TUN network.
for (UnderlyingNetworkInfo info : vpnArray) {
- delta.migrateTun(info.ownerUid, info.iface,
- info.underlyingIfaces.toArray(new String[0]));
+ delta.migrateTun(info.getOwnerUid(), info.getInterface(),
+ info.getUnderlyingInterfaces());
// Filter out debug entries as that may lead to over counting.
delta.filterDebugEntries();
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 19f5e3c..4ee867b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,7 +24,6 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -97,12 +96,12 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
+import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStateSnapshot;
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
-import android.net.NetworkSpecifier;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
import android.net.TrafficStats;
@@ -182,7 +181,7 @@
private static final int MSG_PERFORM_POLL = 1;
// Perform polling, persist network, and register the global alert again.
private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2;
- private static final int MSG_UPDATE_IFACES = 3;
+ private static final int MSG_NOTIFY_NETWORK_STATUS = 3;
// A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent
// deadlock.
private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4;
@@ -380,11 +379,12 @@
performPoll(FLAG_PERSIST_ALL);
break;
}
- case MSG_UPDATE_IFACES: {
+ case MSG_NOTIFY_NETWORK_STATUS: {
// If no cached states, ignore.
if (mLastNetworkStateSnapshots == null) break;
// TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing.
- updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
+ handleNotifyNetworkStatus(
+ mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface);
break;
}
case MSG_PERFORM_POLL_REGISTER_ALERT: {
@@ -475,7 +475,7 @@
@NonNull Looper looper, @NonNull Executor executor,
@NonNull NetworkStatsService service) {
// TODO: Update RatType passively in NSS, instead of querying into the monitor
- // when forceUpdateIface.
+ // when notifyNetworkStatus.
return new NetworkStatsSubscriptionsMonitor(context, looper, executor,
(subscriberId, type) -> service.handleOnCollapsedRatTypeChanged());
}
@@ -972,16 +972,19 @@
}
}
- public void forceUpdateIfaces(
- Network[] defaultNetworks,
- NetworkStateSnapshot[] networkStates,
- String activeIface,
- UnderlyingNetworkInfo[] underlyingNetworkInfos) {
+ /**
+ * Notify {@code NetworkStatsService} about network status changed.
+ */
+ public void notifyNetworkStatus(
+ @NonNull Network[] defaultNetworks,
+ @NonNull NetworkStateSnapshot[] networkStates,
+ @Nullable String activeIface,
+ @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) {
checkNetworkStackPermission(mContext);
final long token = Binder.clearCallingIdentity();
try {
- updateIfaces(defaultNetworks, networkStates, activeIface);
+ handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1245,12 +1248,12 @@
@VisibleForTesting
public void handleOnCollapsedRatTypeChanged() {
// Protect service from frequently updating. Remove pending messages if any.
- mHandler.removeMessages(MSG_UPDATE_IFACES);
+ mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS);
mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay());
+ mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay());
}
- private void updateIfaces(
+ private void handleNotifyNetworkStatus(
Network[] defaultNetworks,
NetworkStateSnapshot[] snapshots,
String activeIface) {
@@ -1258,7 +1261,7 @@
mWakeLock.acquire();
try {
mActiveIface = activeIface;
- updateIfacesLocked(defaultNetworks, snapshots);
+ handleNotifyNetworkStatusLocked(defaultNetworks, snapshots);
} finally {
mWakeLock.release();
}
@@ -1271,10 +1274,10 @@
* they are combined under a single {@link NetworkIdentitySet}.
*/
@GuardedBy("mStatsLock")
- private void updateIfacesLocked(@NonNull Network[] defaultNetworks,
+ private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks,
@NonNull NetworkStateSnapshot[] snapshots) {
if (!mSystemReady) return;
- if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
+ if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()");
// take one last stats snapshot before updating iface mapping. this
// isn't perfect, since the kernel may already be counting traffic from
@@ -1296,9 +1299,9 @@
final ArraySet<String> mobileIfaces = new ArraySet<>();
for (NetworkStateSnapshot snapshot : snapshots) {
final int displayTransport =
- getDisplayTransport(snapshot.networkCapabilities.getTransportTypes());
+ getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes());
final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport);
- final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network);
+ final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork());
final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
: getSubTypeForStateSnapshot(snapshot);
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -1306,7 +1309,7 @@
// Traffic occurring on the base interface is always counted for
// both total usage and UID details.
- final String baseIface = snapshot.linkProperties.getInterfaceName();
+ final String baseIface = snapshot.getLinkProperties().getInterfaceName();
if (baseIface != null) {
findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
@@ -1316,7 +1319,7 @@
// If IMS is metered, then the IMS network usage has already included VT usage.
// VT is considered always metered in framework's layer. If VT is not metered
// per carrier's policy, modem will report 0 usage for VT calls.
- if (snapshot.networkCapabilities.hasCapability(
+ if (snapshot.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
// Copy the identify from IMS one but mark it as metered.
@@ -1364,7 +1367,7 @@
// accounting is explicitly bypassed for traffic from the clat uid.
//
// TODO: This code might be combined to above code.
- for (String iface : snapshot.linkProperties.getAllInterfaceNames()) {
+ for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) {
// baseIface has been handled, so ignore it.
if (TextUtils.equals(baseIface, iface)) continue;
if (iface != null) {
@@ -1383,11 +1386,11 @@
}
private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
- if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR");
}
- final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier();
+ final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier();
if (spec instanceof TelephonyNetworkSpecifier) {
return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
} else {
@@ -1402,11 +1405,11 @@
* transport types do not actually fill this value.
*/
private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) {
- if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return 0;
}
- return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId);
+ return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId());
}
private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet(