Merge "[FUI08] Create NeworkStateSnapshot"
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index 4e3085f..b4a651c 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -16,6 +16,22 @@
package android.net;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -30,6 +46,8 @@
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -154,8 +172,30 @@
* needed in terms of {@link NetworkCapabilities} features
*/
public static class Builder {
+ /**
+ * Capabilities that are currently compatible with VCN networks.
+ */
+ private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
+ NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_DUN,
+ NET_CAPABILITY_FOREGROUND,
+ NET_CAPABILITY_INTERNET,
+ NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_METERED,
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_NOT_ROAMING,
+ NET_CAPABILITY_NOT_SUSPENDED,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+ NET_CAPABILITY_TRUSTED,
+ NET_CAPABILITY_VALIDATED);
+
private final NetworkCapabilities mNetworkCapabilities;
+ // A boolean that represents the user modified NOT_VCN_MANAGED capability.
+ private boolean mModifiedNotVcnManaged = false;
+
/**
* Default constructor for Builder.
*/
@@ -177,6 +217,7 @@
// maybeMarkCapabilitiesRestricted() doesn't add back.
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
nc.maybeMarkCapabilitiesRestricted();
+ deduceNotVcnManagedCapability(nc);
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
}
@@ -193,6 +234,9 @@
*/
public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -204,6 +248,9 @@
*/
public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.removeCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -261,6 +308,9 @@
@NonNull
public Builder clearCapabilities() {
mNetworkCapabilities.clearAll();
+ // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
+ // should not be add back later.
+ mModifiedNotVcnManaged = true;
return this;
}
@@ -380,6 +430,25 @@
mNetworkCapabilities.setSignalStrength(signalStrength);
return this;
}
+
+ /**
+ * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
+ * and user intention, which includes:
+ * 1. For the requests that don't have anything besides
+ * {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
+ * allow the callers automatically utilize VCN networks if available.
+ * 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
+ * do not alter them to allow user fire request that suits their need.
+ *
+ * @hide
+ */
+ private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
+ if (mModifiedNotVcnManaged) return;
+ for (final int cap : nc.getCapabilities()) {
+ if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
+ }
+ nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ }
}
// implement the Parcelable interface
diff --git a/framework/src/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
index 9ccb04a..b5e8a61 100644
--- a/framework/src/android/net/NetworkUtils.java
+++ b/framework/src/android/net/NetworkUtils.java
@@ -91,7 +91,8 @@
* this socket will go directly to the underlying network, so its traffic will not be
* forwarded through the VPN.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553,
+ publicAlternatives = "Use {@link android.net.VpnService#protect} instead.")
public static native boolean protectFromVpn(FileDescriptor fd);
/**
diff --git a/framework/src/android/net/VpnTransportInfo.java b/framework/src/android/net/VpnTransportInfo.java
index 0242ba0..340141b 100644
--- a/framework/src/android/net/VpnTransportInfo.java
+++ b/framework/src/android/net/VpnTransportInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/framework/src/android/net/util/MultinetworkPolicyTracker.java b/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 85e3fa3..43fffd7 100644
--- a/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -40,6 +40,8 @@
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
/**
* A class to encapsulate management of the "Smart Networking" capability of
@@ -73,6 +75,32 @@
private volatile int mMeteredMultipathPreference;
private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ // Mainline module can't use internal HandlerExecutor, so add an identical executor here.
+ private static class HandlerExecutor implements Executor {
+ @NonNull
+ private final Handler mHandler;
+
+ HandlerExecutor(@NonNull Handler handler) {
+ mHandler = handler;
+ }
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+ }
+
+ @VisibleForTesting
+ protected class ActiveDataSubscriptionIdChangedListener extends PhoneStateListener
+ implements PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ mActiveSubId = subId;
+ reevaluateInternal();
+ }
+ }
+
public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
}
@@ -93,14 +121,8 @@
}
};
- ctx.getSystemService(TelephonyManager.class).listen(
- new PhoneStateListener(handler.getLooper()) {
- @Override
- public void onActiveDataSubscriptionIdChanged(int subId) {
- mActiveSubId = subId;
- reevaluateInternal();
- }
- }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+ ctx.getSystemService(TelephonyManager.class).registerPhoneStateListener(
+ new HandlerExecutor(handler), new ActiveDataSubscriptionIdChangedListener());
updateAvoidBadWifi();
updateMeteredMultipathPreference();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f4138d1..542d527 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -44,6 +44,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
@@ -91,7 +92,6 @@
import android.net.IDnsResolver;
import android.net.INetd;
import android.net.INetworkActivityListener;
-import android.net.INetworkManagementEventObserver;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
@@ -194,6 +194,7 @@
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
@@ -214,7 +215,6 @@
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.utils.PriorityDump;
@@ -332,6 +332,7 @@
private INetworkStatsService mStatsService;
private NetworkPolicyManager mPolicyManager;
private NetworkPolicyManagerInternal mPolicyManagerInternal;
+ private final NetdCallback mNetdCallback;
/**
* TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple
@@ -1204,6 +1205,13 @@
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd);
+ mNetdCallback = new NetdCallback();
+ try {
+ mNetd.registerUnsolicitedEventListener(mNetdCallback);
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Error registering event listener :" + e);
+ }
+
mSettingsObserver = new SettingsObserver(mContext, mHandler);
registerSettingsCallbacks();
@@ -1241,6 +1249,7 @@
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
netCap.setSingleUid(uid);
return netCap;
@@ -1255,6 +1264,7 @@
int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > TYPE_NONE) {
netCap.addTransportType(transportType);
@@ -8649,6 +8659,14 @@
notifyDataStallSuspected(p, network.getNetId());
}
+ private class NetdCallback extends BaseNetdUnsolicitedEventListener {
+ @Override
+ public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel,
+ long timestampNs, int uid) {
+ mNetworkActivityTracker.setAndReportNetworkActive(isActive, timerLabel, timestampNs);
+ }
+ }
+
private final LegacyNetworkActivityTracker mNetworkActivityTracker;
/**
@@ -8659,7 +8677,6 @@
private static final int NO_UID = -1;
private final Context mContext;
private final INetd mNetd;
- private final INetworkManagementService mNMS;
private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
new RemoteCallbackList<>();
// Indicate the current system default network activity is active or not.
@@ -8682,41 +8699,27 @@
LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
@NonNull INetworkManagementService nms, @NonNull INetd netd) {
mContext = context;
- mNMS = nms;
mNetd = netd;
mHandler = handler;
- try {
- mNMS.registerObserver(mDataActivityObserver);
- } catch (RemoteException e) {
- loge("Error registering observer :" + e);
- }
}
- // TODO: Migrate away the dependency with INetworkManagementEventObserver.
- private final INetworkManagementEventObserver mDataActivityObserver =
- new BaseNetworkObserver() {
- @Override
- public void interfaceClassDataActivityChanged(int transportType, boolean active,
- long tsNanos, int uid) {
- sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
- tsNanos);
- synchronized (mActiveIdleTimers) {
- mNetworkActive = active;
- // If there are no idle timers, it means that system is not monitoring
- // activity, so the system default network for those default network
- // unspecified apps is always considered active.
- //
- // TODO: If the mActiveIdleTimers is empty, netd will actually not send
- // any network activity change event. Whenever this event is received,
- // the mActiveIdleTimers should be always not empty. The legacy behavior
- // is no-op. Remove to refer to mNetworkActive only.
- if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
- mHandler.sendMessage(
- mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
- }
- }
- }
- };
+ public void setAndReportNetworkActive(boolean active, int transportType, long tsNanos) {
+ sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos);
+ synchronized (mActiveIdleTimers) {
+ mNetworkActive = active;
+ // If there are no idle timers, it means that system is not monitoring
+ // activity, so the system default network for those default network
+ // unspecified apps is always considered active.
+ //
+ // TODO: If the mActiveIdleTimers is empty, netd will actually not send
+ // any network activity change event. Whenever this event is received,
+ // the mActiveIdleTimers should be always not empty. The legacy behavior
+ // is no-op. Remove to refer to mNetworkActive only.
+ if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
+ }
+ }
+ }
// The network activity should only be updated from ConnectivityService handler thread
// when mActiveIdleTimers lock is held.
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index ad5bbf2..18a9331 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -55,14 +55,14 @@
.build()
private val dataFromPasspoint = CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
.setCaptive(true)
.apply {
if (SdkLevel.isAtLeastS()) {
setVenueFriendlyName("venue friendly name")
+ setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+ setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
}
}
.build()
@@ -96,28 +96,28 @@
if (SdkLevel.isAtLeastS()) {
assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
- }
- assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint")) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/other"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/passpoint")) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/other"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint")) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/other"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/passpoint")) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/other"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ }
}
@Test
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index dc9e587..e1da3d0 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -84,6 +85,7 @@
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
diff --git a/tests/net/java/android/net/NetworkIdentityTest.kt b/tests/net/java/android/net/NetworkIdentityTest.kt
new file mode 100644
index 0000000..eb2b85c
--- /dev/null
+++ b/tests/net/java/android/net/NetworkIdentityTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net
+
+import android.net.NetworkIdentity.OEM_NONE
+import android.net.NetworkIdentity.OEM_PAID
+import android.net.NetworkIdentity.OEM_PRIVATE
+import android.net.NetworkIdentity.getOemBitfield
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertEquals
+
+@RunWith(JUnit4::class)
+class NetworkIdentityTest {
+ @Test
+ fun testGetOemBitfield() {
+ val oemNone = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
+ }
+ val oemPaid = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
+ }
+ val oemPrivate = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
+ }
+ val oemAll = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
+ }
+
+ assertEquals(getOemBitfield(oemNone), OEM_NONE)
+ assertEquals(getOemBitfield(oemPaid), OEM_PAID)
+ assertEquals(getOemBitfield(oemPrivate), OEM_PRIVATE)
+ assertEquals(getOemBitfield(oemAll), OEM_PAID or OEM_PRIVATE)
+ }
+}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index b39555d..27224c2 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -20,14 +20,23 @@
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.NetworkIdentity.SUBTYPE_COMBINED
+import android.net.NetworkIdentity.OEM_NONE;
+import android.net.NetworkIdentity.OEM_PAID;
+import android.net.NetworkIdentity.OEM_PRIVATE;
import android.net.NetworkIdentity.buildNetworkIdentity
import android.net.NetworkStats.DEFAULT_NETWORK_ALL
import android.net.NetworkStats.METERED_ALL
import android.net.NetworkStats.ROAMING_ALL
+import android.net.NetworkTemplate.MATCH_ETHERNET
import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
+import android.net.NetworkTemplate.OEM_MANAGED_ALL
+import android.net.NetworkTemplate.OEM_MANAGED_NO
+import android.net.NetworkTemplate.OEM_MANAGED_YES
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
import android.telephony.TelephonyManager
import com.android.testutils.assertParcelSane
@@ -37,9 +46,11 @@
import org.junit.runners.JUnit4
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
+import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
+import kotlin.test.fail
private const val TEST_IMSI1 = "imsi1"
private const val TEST_IMSI2 = "imsi2"
@@ -57,13 +68,18 @@
private fun buildNetworkState(
type: Int,
subscriberId: String? = null,
- ssid: String? = null
+ ssid: String? = null,
+ oemManaged: Int = OEM_NONE,
): NetworkState {
val lp = LinkProperties()
val caps = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
setSSID(ssid)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID,
+ (oemManaged and OEM_PAID) == OEM_PAID)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
+ (oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
}
return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId)
}
@@ -136,11 +152,15 @@
@Test
fun testParcelUnparcel() {
val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE)
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE,
+ OEM_MANAGED_ALL)
val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 0)
- assertParcelSane(templateMobile, 8)
- assertParcelSane(templateWifi, 8)
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL)
+ val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES)
+ assertParcelSane(templateMobile, 9)
+ assertParcelSane(templateWifi, 9)
+ assertParcelSane(templateOem, 9)
}
// Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
@@ -152,4 +172,81 @@
assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
}
}
+
+ @Test
+ fun testOemNetworkConstants() {
+ val constantValues = arrayOf(OEM_MANAGED_YES, OEM_MANAGED_ALL, OEM_MANAGED_NO,
+ OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
+
+ // Verify that "not OEM managed network" constants are equal.
+ assertEquals(OEM_MANAGED_NO, OEM_NONE);
+
+ // Verify the constants don't conflict.
+ assertEquals(constantValues.size, constantValues.distinct().count())
+ }
+
+ /**
+ * Helper to enumerate and assert OEM managed wifi and mobile {@code NetworkTemplate}s match
+ * their the appropriate OEM managed {@code NetworkIdentity}s.
+ *
+ * @param networkType {@code TYPE_MOBILE} or {@code TYPE_WIFI}
+ * @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the
+ * networkType.
+ * @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is
+ * {@code TYPE_MOBILE}. May be left as null when matchType is
+ * {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}.
+ * @param templateSsid Top be populated with {@code TEST_SSID*} only if networkType is
+ * {@code TYPE_WIFI}. May be left as null when matchType is
+ * {@link NetworkTemplate.MATCH_WIFI_WILDCARD}.
+ * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
+ * one of {@code TEST_SSID*}.
+ */
+ private fun matchOemManagedIdent(networkType: Int, matchType:Int, subscriberId: String? = null,
+ templateSsid: String? = null, identSsid: String? = null) {
+ val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
+ // A null subscriberId needs a null matchSubscriberIds argument as well.
+ val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId)
+
+ val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_YES)
+ val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL)
+
+ for (identityOemManagedState in oemManagedStates) {
+ val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType,
+ subscriberId, identSsid, identityOemManagedState), /*defaultNetwork=*/false,
+ /*subType=*/0)
+
+ // Create a template with each OEM managed type and match it against the NetworkIdentity
+ for (templateOemManagedState in oemManagedStates) {
+ val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ NETWORK_TYPE_ALL, templateOemManagedState)
+ if (identityOemManagedState == templateOemManagedState) {
+ template.assertMatches(ident)
+ } else {
+ template.assertDoesNotMatch(ident)
+ }
+ }
+ // OEM_MANAGED_ALL ignores OEM state.
+ templateOemAll.assertMatches(ident)
+ if (identityOemManagedState == OEM_NONE) {
+ // OEM_MANAGED_YES matches everything except OEM_NONE.
+ templateOemYes.assertDoesNotMatch(ident)
+ } else {
+ templateOemYes.assertMatches(ident)
+ }
+ }
+ }
+
+ @Test
+ fun testOemManagedMatchesIdent() {
+ matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1)
+ matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD)
+ matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateSsid = TEST_SSID1,
+ identSsid = TEST_SSID1)
+ matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, identSsid = TEST_SSID1)
+ }
}
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index 866f38c..d04c87b 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
new file mode 100644
index 0000000..9b0cfa9
--- /dev/null
+++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
+import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
+import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdChangedListener
+import android.provider.Settings
+import android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI
+import android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import android.test.mock.MockContentResolver
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.R
+import com.android.internal.util.test.FakeSettingsProvider
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.argThat
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+/**
+ * Tests for [MultinetworkPolicyTracker].
+ *
+ * Build, install and run with:
+ * atest android.net.util.MultinetworkPolicyTrackerTest
+ */
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class MultinetworkPolicyTrackerTest {
+ private val resources = mock(Resources::class.java).also {
+ doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
+ }
+ private val telephonyManager = mock(TelephonyManager::class.java)
+ private val subscriptionManager = mock(SubscriptionManager::class.java).also {
+ doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt())
+ }
+ private val resolver = MockContentResolver().apply {
+ addProvider(Settings.AUTHORITY, FakeSettingsProvider()) }
+ private val context = mock(Context::class.java).also {
+ doReturn(Context.TELEPHONY_SERVICE).`when`(it)
+ .getSystemServiceName(TelephonyManager::class.java)
+ doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
+ doReturn(subscriptionManager).`when`(it)
+ .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
+ doReturn(resolver).`when`(it).contentResolver
+ doReturn(resources).`when`(it).resources
+ doReturn(it).`when`(it).createConfigurationContext(any())
+ Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
+ }
+ private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
+
+ private fun assertMultipathPreference(preference: Int) {
+ Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
+ preference.toString())
+ tracker.updateMeteredMultipathPreference()
+ assertEquals(preference, tracker.meteredMultipathPreference)
+ }
+
+ @Test
+ fun testUpdateMeteredMultipathPreference() {
+ assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
+ assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY)
+ assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE)
+ }
+
+ @Test
+ fun testUpdateAvoidBadWifi() {
+ Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
+ assertTrue(tracker.updateAvoidBadWifi())
+ assertFalse(tracker.avoidBadWifi)
+
+ doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
+ assertTrue(tracker.updateAvoidBadWifi())
+ assertTrue(tracker.avoidBadWifi)
+ }
+
+ @Test
+ fun testOnActiveDataSubscriptionIdChanged() {
+ val testSubId = 1000
+ val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */,
+ "TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */,
+ "123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */,
+ ""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */,
+ "1"/* cardString */)
+ doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId)
+
+ // Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in
+ // MultinetworkPolicyTracker should be also updated after subId changed.
+ Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
+ Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
+ MULTIPATH_PREFERENCE_PERFORMANCE.toString())
+
+ val listenerCaptor = ArgumentCaptor.forClass(
+ ActiveDataSubscriptionIdChangedListener::class.java)
+ verify(telephonyManager, times(1))
+ .registerPhoneStateListener(any(), listenerCaptor.capture())
+ val listener = listenerCaptor.value
+ listener.onActiveDataSubscriptionIdChanged(testSubId)
+
+ // Check it get resource value with test sub id.
+ verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId)
+ verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 })
+
+ // Check if avoidBadWifi and meteredMultipathPreference values have been updated.
+ assertFalse(tracker.avoidBadWifi)
+ assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference)
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index fbeebe5..bb822d8 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2798,6 +2798,10 @@
NetworkCapabilities filter = new NetworkCapabilities();
filter.addCapability(capability);
+ // Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add
+ // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
+ // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
+ filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
handlerThread.start();
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -4144,6 +4148,7 @@
handlerThread.start();
NetworkCapabilities filter = new NetworkCapabilities()
.addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_INTERNET);
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter, mCsHandlerThread);
@@ -6048,6 +6053,7 @@
.addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkDownstreamBandwidthKbps(10);
final NetworkCapabilities wifiNc = new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
@@ -6056,6 +6062,7 @@
.addCapability(NET_CAPABILITY_NOT_ROAMING)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkUpstreamBandwidthKbps(20);
mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
@@ -7748,19 +7755,13 @@
mWiFiNetworkAgent.removeCapability(testCap);
callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
- // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
- // it.
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
- }
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
mCellNetworkAgent.removeCapability(testCap);
callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
callbackWithoutCap.assertNoCallback();
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkClearDefault();
- }
+ verify(mMockNetd).networkClearDefault();
mCm.unregisterNetworkCallback(callbackWithCap);
mCm.unregisterNetworkCallback(callbackWithoutCap);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 435c3c0..505ff9b 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkIdentity.OEM_NONE;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
@@ -213,7 +214,7 @@
final NetworkStats.Entry entry = new NetworkStats.Entry();
final NetworkIdentitySet identSet = new NetworkIdentitySet();
identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- TEST_IMSI, null, false, true, true));
+ TEST_IMSI, null, false, true, true, OEM_NONE));
int myUid = Process.myUid();
int otherUidInSameUser = Process.myUid() + 1;
@@ -468,7 +469,7 @@
final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
final NetworkIdentitySet ident = new NetworkIdentitySet();
ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
- false, true, true));
+ false, true, true, OEM_NONE));
large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index 291efc7..9fa1c50 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkIdentity.OEM_NONE;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.METERED_NO;
@@ -220,7 +221,7 @@
identSet.add(new NetworkIdentity(
TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
IMSI_1, null /* networkId */, false /* roaming */, true /* metered */,
- true /* defaultNetwork */));
+ true /* defaultNetwork */, OEM_NONE));
return identSet;
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index d644739..54d6fb9 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -21,6 +21,9 @@
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkIdentity.OEM_NONE;
+import static android.net.NetworkIdentity.OEM_PAID;
+import static android.net.NetworkIdentity.OEM_PRIVATE;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
@@ -40,7 +43,10 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
+import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
+import static android.net.NetworkTemplate.OEM_MANAGED_NO;
+import static android.net.NetworkTemplate.OEM_MANAGED_YES;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
import static android.net.NetworkTemplate.buildTemplateWifi;
@@ -643,6 +649,116 @@
assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2);
}
+ @Test
+ public void testMobileStatsOemManaged() throws Exception {
+ final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID);
+
+ final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE);
+
+ final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_PAID | OEM_PRIVATE);
+
+ final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES);
+
+ final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
+ /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO);
+
+ // OEM_PAID network comes online.
+ NetworkState[] states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+ new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 36L, 41L, 24L, 96L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // OEM_PRIVATE network comes online.
+ states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+ new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 49L, 71L, 72L, 48L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // OEM_PAID + OEM_PRIVATE network comes online.
+ states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false,
+ new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
+ NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 57L, 86L, 83L, 93L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // OEM_NONE network comes online.
+ states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 29L, 73L, 34L, 31L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // Verify OEM_PAID template gets only relevant stats.
+ assertUidTotal(templateOemPaid, UID_RED, 36L, 41L, 24L, 96L, 0);
+
+ // Verify OEM_PRIVATE template gets only relevant stats.
+ assertUidTotal(templateOemPrivate, UID_RED, 49L, 71L, 72L, 48L, 0);
+
+ // Verify OEM_PAID + OEM_PRIVATE template gets only relevant stats.
+ assertUidTotal(templateOemAll, UID_RED, 57L, 86L, 83L, 93L, 0);
+
+ // Verify OEM_NONE sees only non-OEM managed stats.
+ assertUidTotal(templateOemNone, UID_RED, 29L, 73L, 34L, 31L, 0);
+
+ // Verify OEM_MANAGED_YES sees all OEM managed stats.
+ assertUidTotal(templateOemYes, UID_RED,
+ 36L + 49L + 57L,
+ 41L + 71L + 86L,
+ 24L + 72L + 83L,
+ 96L + 48L + 93L, 0);
+
+ // Verify ALL_MOBILE template gets both OEM managed and non-OEM managed stats.
+ assertUidTotal(sTemplateImsi1, UID_RED,
+ 36L + 49L + 57L + 29L,
+ 41L + 71L + 86L + 73L,
+ 24L + 72L + 83L + 34L,
+ 96L + 48L + 93L + 31L, 0);
+ }
+
// TODO: support per IMSI state
private void setMobileRatTypeAndWaitForIdle(int ratType) {
when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString()))
@@ -1488,6 +1604,20 @@
return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null);
}
+ private static NetworkState buildOemManagedMobileState(String subscriberId, boolean isRoaming,
+ int[] oemNetCapabilities) {
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(TEST_IFACE);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
+ for (int nc : oemNetCapabilities) {
+ capabilities.setCapability(nc, true);
+ }
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId);
+ }
+
private long getElapsedRealtime() {
return mElapsedRealtime;
}