Merge "Verify kernel implementation of AES-XCBC"
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 8adcbd9..36a2f10 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -48,6 +48,7 @@
import android.net.util.SharedLog;
import android.net.util.TetheringUtils.ForwardedStats;
import android.os.Handler;
+import android.os.SystemClock;
import android.system.ErrnoException;
import android.text.TextUtils;
import android.util.Log;
@@ -773,6 +774,12 @@
}
pw.decreaseIndent();
+ pw.println("BPF stats:");
+ pw.increaseIndent();
+ dumpBpfStats(pw);
+ pw.decreaseIndent();
+ pw.println();
+
pw.println("Forwarding rules:");
pw.increaseIndent();
dumpIpv6UpstreamRules(pw);
@@ -800,6 +807,22 @@
upstreamIfindex), stats.toString()));
}
}
+ private void dumpBpfStats(@NonNull IndentingPrintWriter pw) {
+ try (BpfMap<TetherStatsKey, TetherStatsValue> map = mDeps.getBpfStatsMap()) {
+ if (map == null) {
+ pw.println("No BPF stats map");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("<empty>");
+ }
+ map.forEach((k, v) -> {
+ pw.println(String.format("%s: %s", k, v));
+ });
+ } catch (ErrnoException e) {
+ pw.println("Error dumping BPF stats map: " + e);
+ }
+ }
private void dumpIpv6ForwardingRules(@NonNull IndentingPrintWriter pw) {
if (mIpv6ForwardingRules.size() == 0) {
@@ -849,7 +872,7 @@
}
}
- private String ipv4RuleToString(Tether4Key key, Tether4Value value) {
+ private String ipv4RuleToString(long now, Tether4Key key, Tether4Value value) {
final String private4, public4, dst4;
try {
private4 = InetAddress.getByAddress(key.src4).getHostAddress();
@@ -858,29 +881,43 @@
} catch (UnknownHostException impossible) {
throw new AssertionError("4-byte array not valid IPv4 address!");
}
- return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d",
+ long ageMs = (now - value.lastUsed) / 1_000_000;
+ return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d %dms",
key.dstMac, key.iif, getIfName(key.iif), private4, key.srcPort,
value.oif, getIfName(value.oif),
- public4, value.srcPort, dst4, key.dstPort);
+ public4, value.srcPort, dst4, key.dstPort, ageMs);
+ }
+
+ private void dumpIpv4ForwardingRuleMap(long now, BpfMap<Tether4Key, Tether4Value> map,
+ IndentingPrintWriter pw) throws ErrnoException {
+ if (map == null) {
+ pw.println("No IPv4 support");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("No rules");
+ return;
+ }
+ map.forEach((k, v) -> pw.println(ipv4RuleToString(now, k, v)));
}
private void dumpIpv4ForwardingRules(IndentingPrintWriter pw) {
- try (BpfMap<Tether4Key, Tether4Value> map = mDeps.getBpfUpstream4Map()) {
- if (map == null) {
- pw.println("No IPv4 support");
- return;
- }
- if (map.isEmpty()) {
- pw.println("No IPv4 rules");
- return;
- }
- pw.println("IPv4: [inDstMac] iif(iface) src -> nat -> dst");
+ final long now = SystemClock.elapsedRealtimeNanos();
+
+ try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map();
+ BpfMap<Tether4Key, Tether4Value> downstreamMap = mDeps.getBpfDownstream4Map()) {
+ pw.println("IPv4 Upstream: [inDstMac] iif(iface) src -> nat -> dst");
pw.increaseIndent();
- map.forEach((k, v) -> pw.println(ipv4RuleToString(k, v)));
+ dumpIpv4ForwardingRuleMap(now, upstreamMap, pw);
+ pw.decreaseIndent();
+
+ pw.println("IPv4 Downstream: [inDstMac] iif(iface) src -> nat -> dst");
+ pw.increaseIndent();
+ dumpIpv4ForwardingRuleMap(now, downstreamMap, pw);
+ pw.decreaseIndent();
} catch (ErrnoException e) {
pw.println("Error dumping IPv4 map: " + e);
}
- pw.decreaseIndent();
}
/**
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 90d821b..82842bc 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -817,6 +817,7 @@
final int originalOwnerUid = getOwnerUid();
final int[] originalAdministratorUids = getAdministratorUids();
final TransportInfo originalTransportInfo = getTransportInfo();
+ final Set<Integer> originalSubIds = getSubscriptionIds();
clearAll();
if (0 != (originalCapabilities & NET_CAPABILITY_NOT_RESTRICTED)) {
// If the test network is not restricted, then it is only allowed to declare some
@@ -825,6 +826,9 @@
mTransportTypes =
(originalTransportTypes & UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS)
| (1 << TRANSPORT_TEST);
+
+ // SubIds are only allowed for Test Networks that only declare TRANSPORT_TEST.
+ setSubscriptionIds(originalSubIds);
} else {
// If the test transport is restricted, then it may declare any transport.
mTransportTypes = (originalTransportTypes | (1 << TRANSPORT_TEST));
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 15b666a..913b3f3 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -398,6 +398,32 @@
}
/**
+ * The priority value is used when issue uid ranges rules to netd. Netd will use the priority
+ * value and uid ranges to generate corresponding ip rules specific to the given preference.
+ * Thus, any device originated data traffic of the applied uids can be routed to the altered
+ * default network which has highest priority.
+ *
+ * Note: The priority value should be in 0~1000. Larger value means lower priority, see
+ * {@link NativeUidRangeConfig}.
+ */
+ // This is default priority value for those NetworkRequests which doesn't have preference to
+ // alter default network and use the global one.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_NONE = 0;
+ // Used by automotive devices to set the network preferences used to direct traffic at an
+ // application level. See {@link #setOemNetworkPreference}.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_OEM = 10;
+ // Request that a user profile is put by default on a network matching a given preference.
+ // See {@link #setProfileNetworkPreference}.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_PROFILE = 20;
+ // Set by MOBILE_DATA_PREFERRED_UIDS setting. Use mobile data in preference even when
+ // higher-priority networks are connected.
+ @VisibleForTesting
+ static final int DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED = 30;
+
+ /**
* used internally to clear a wakelock when transitioning
* from one net to another. Clear happens when we get a new
* network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
@@ -1516,7 +1542,7 @@
}
// Note that registering observer for setting do not get initial callback when registering,
- // callers might have self-initialization to update status if need.
+ // callers must fetch the initial value of the setting themselves if needed.
private void registerSettingsCallbacks() {
// Watch for global HTTP proxy changes.
mSettingsObserver.observe(
@@ -4146,8 +4172,10 @@
final NetworkAgentInfo satisfier = nri.getSatisfier();
if (null != satisfier) {
try {
+ // TODO: Passing default network priority to netd.
mNetd.networkRemoveUidRanges(satisfier.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
+ toUidRangeStableParcels(nri.getUids())
+ /* nri.getDefaultNetworkPriority() */);
} catch (RemoteException e) {
loge("Exception setting network preference default network", e);
}
@@ -5592,6 +5620,13 @@
// maximum limit of registered callbacks per UID.
final int mAsUid;
+ // Default network priority of this request.
+ private final int mDefaultNetworkPriority;
+
+ int getDefaultNetworkPriority() {
+ return mDefaultNetworkPriority;
+ }
+
// In order to preserve the mapping of NetworkRequest-to-callback when apps register
// callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
// maintained for keying off of. This is only a concern when the original nri
@@ -5621,12 +5656,13 @@
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
@Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
- this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag);
+ this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag,
+ DEFAULT_NETWORK_PRIORITY_NONE);
}
NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
- @Nullable String callingAttributionTag) {
+ @Nullable String callingAttributionTag, final int defaultNetworkPriority) {
ensureAllNetworkRequestsHaveType(r);
mRequests = initializeRequests(r);
mNetworkRequestForCallback = requestForCallback;
@@ -5644,6 +5680,7 @@
*/
mCallbackFlags = NetworkCallback.FLAG_NONE;
mCallingAttributionTag = callingAttributionTag;
+ mDefaultNetworkPriority = defaultNetworkPriority;
}
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
@@ -5673,6 +5710,7 @@
mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
+ mDefaultNetworkPriority = DEFAULT_NETWORK_PRIORITY_NONE;
linkDeathRecipient();
}
@@ -5712,15 +5750,18 @@
mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
+ mDefaultNetworkPriority = DEFAULT_NETWORK_PRIORITY_NONE;
linkDeathRecipient();
}
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
- this(asUid, Collections.singletonList(r));
+ this(asUid, Collections.singletonList(r), DEFAULT_NETWORK_PRIORITY_NONE);
}
- NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) {
- this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */);
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
+ final int defaultNetworkPriority) {
+ this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */,
+ defaultNetworkPriority);
}
// True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -7377,9 +7418,13 @@
maybeCloseSockets(nai, ranges, exemptUids);
try {
if (add) {
- mNetd.networkAddUidRanges(nai.network.netId, ranges);
+ // TODO: Passing default network priority to netd.
+ mNetd.networkAddUidRanges(nai.network.netId, ranges
+ /* DEFAULT_NETWORK_PRIORITY_NONE */);
} else {
- mNetd.networkRemoveUidRanges(nai.network.netId, ranges);
+ // TODO: Passing default network priority to netd.
+ mNetd.networkRemoveUidRanges(nai.network.netId, ranges
+ /* DEFAULT_NETWORK_PRIORITY_NONE */);
}
} catch (Exception e) {
loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges +
@@ -7690,14 +7735,18 @@
+ " any applications to set as the default." + nri);
}
if (null != newDefaultNetwork) {
+ // TODO: Passing default network priority to netd.
mNetd.networkAddUidRanges(
newDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
+ toUidRangeStableParcels(nri.getUids())
+ /* nri.getDefaultNetworkPriority() */);
}
if (null != oldDefaultNetwork) {
+ // TODO: Passing default network priority to netd.
mNetd.networkRemoveUidRanges(
oldDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
+ toUidRangeStableParcels(nri.getUids())
+ /* nri.getDefaultNetworkPriority() */);
}
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception setting app default network", e);
@@ -9755,7 +9804,8 @@
nrs.add(createDefaultInternetRequestForTransport(
TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
- final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
+ final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs,
+ DEFAULT_NETWORK_PRIORITY_PROFILE);
result.add(nri);
}
return result;
@@ -9825,7 +9875,8 @@
ranges.add(new UidRange(uid, uid));
}
setNetworkRequestUids(requests, ranges);
- nris.add(new NetworkRequestInfo(Process.myUid(), requests));
+ nris.add(new NetworkRequestInfo(Process.myUid(), requests,
+ DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED));
return nris;
}
@@ -10069,7 +10120,7 @@
private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences(
@NonNull final OemNetworkPreferences preference) {
- final SparseArray<Set<Integer>> uids = new SparseArray<>();
+ final SparseArray<Set<Integer>> prefToUids = new SparseArray<>();
final PackageManager pm = mContext.getPackageManager();
final List<UserHandle> users =
mContext.getSystemService(UserManager.class).getUserHandles(true);
@@ -10077,29 +10128,29 @@
if (VDBG || DDBG) {
log("No users currently available for setting the OEM network preference.");
}
- return uids;
+ return prefToUids;
}
for (final Map.Entry<String, Integer> entry :
preference.getNetworkPreferences().entrySet()) {
@OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
- try {
- final int uid = pm.getApplicationInfo(entry.getKey(), 0).uid;
- if (!uids.contains(pref)) {
- uids.put(pref, new ArraySet<>());
+ // Add the rules for all users as this policy is device wide.
+ for (final UserHandle user : users) {
+ try {
+ final int uid = pm.getApplicationInfoAsUser(entry.getKey(), 0, user).uid;
+ if (!prefToUids.contains(pref)) {
+ prefToUids.put(pref, new ArraySet<>());
+ }
+ prefToUids.get(pref).add(uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Although this may seem like an error scenario, it is ok that uninstalled
+ // packages are sent on a network preference as the system will watch for
+ // package installations associated with this network preference and update
+ // accordingly. This is done to minimize race conditions on app install.
+ continue;
}
- for (final UserHandle ui : users) {
- // Add the rules for all users as this policy is device wide.
- uids.get(pref).add(ui.getUid(uid));
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Although this may seem like an error scenario, it is ok that uninstalled
- // packages are sent on a network preference as the system will watch for
- // package installations associated with this network preference and update
- // accordingly. This is done so as to minimize race conditions on app install.
- continue;
}
}
- return uids;
+ return prefToUids;
}
private NetworkRequestInfo createNriFromOemNetworkPreferences(
@@ -10135,7 +10186,8 @@
ranges.add(new UidRange(uid, uid));
}
setNetworkRequestUids(requests, ranges);
- return new NetworkRequestInfo(Process.myUid(), requests);
+ return new NetworkRequestInfo(
+ Process.myUid(), requests, DEFAULT_NETWORK_PRIORITY_OEM);
}
private NetworkRequest createUnmeteredNetworkRequest() {
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
index 09873f4..fffd2be 100644
--- a/service/src/com/android/server/TestNetworkService.java
+++ b/service/src/com/android/server/TestNetworkService.java
@@ -48,7 +48,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetworkStackConstants;
-import com.android.net.module.util.PermissionUtils;
import java.io.UncheckedIOException;
import java.net.Inet4Address;
@@ -123,6 +122,8 @@
addr.getPrefixLength());
}
+ NetdUtils.setInterfaceUp(mNetd, iface);
+
return new TestNetworkInterface(tunIntf, iface);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -324,14 +325,6 @@
}
try {
- final long token = Binder.clearCallingIdentity();
- try {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- NetdUtils.setInterfaceUp(mNetd, iface);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
// Synchronize all accesses to mTestNetworkTracker to prevent the case where:
// 1. TestNetworkAgent successfully binds to death of binder
// 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 1afbfb0..7d30056 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -106,6 +106,8 @@
private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
+ private static final String EMPTY_STRING = "";
+
protected static final int TYPE_COMPONENT_ACTIVTIY = 0;
protected static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1;
@@ -206,6 +208,8 @@
final String resultData = getResultData();
if (resultData == null) {
Log.e(TAG, "Received null data from ordered intent");
+ // Offer an empty string so that the code waiting for the result can return.
+ result.offer(EMPTY_STRING);
return;
}
result.offer(resultData);
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 0075b54..1d84a1b 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -151,6 +151,7 @@
import com.android.networkstack.apishim.common.ConnectivityManagerShim;
import com.android.testutils.CompatUtil;
import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRuleKt;
import com.android.testutils.RecorderCallback.CallbackEntry;
import com.android.testutils.SkipPresubmit;
@@ -660,6 +661,31 @@
.build();
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testIsPrivateDnsBroken() throws InterruptedException {
+ final String invalidPrivateDnsServer = "invalidhostname.example.com";
+ final String goodPrivateDnsServer = "dns.google";
+ mCtsNetUtils.storePrivateDnsSetting();
+ final TestableNetworkCallback cb = new TestableNetworkCallback();
+ mCm.registerNetworkCallback(makeWifiNetworkRequest(), cb);
+ try {
+ // Verifying the good private DNS sever
+ mCtsNetUtils.setPrivateDnsStrictMode(goodPrivateDnsServer);
+ final Network networkForPrivateDns = mCtsNetUtils.ensureWifiConnected();
+ cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> (!((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+ .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork()));
+
+ // Verifying the broken private DNS sever
+ mCtsNetUtils.setPrivateDnsStrictMode(invalidPrivateDnsServer);
+ cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED, NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> (((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+ .isPrivateDnsBroken()) && networkForPrivateDns.equals(entry.getNetwork()));
+ } finally {
+ mCtsNetUtils.restorePrivateDnsSetting();
+ }
+ }
+
/**
* Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
* see if we get a callback for the TRANSPORT_WIFI transport type being available.
diff --git a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
index 899295a..6bd2bd5 100644
--- a/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
+++ b/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
@@ -24,8 +24,8 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -52,6 +52,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkStatsManagerTest {
+ private static final String TEST_SUBSCRIBER_ID = "subid";
private @Mock INetworkStatsService mService;
private @Mock INetworkStatsSession mStatsSession;
@@ -69,7 +70,6 @@
@Test
public void testQueryDetails() throws RemoteException {
- final String subscriberId = "subid";
final long startTime = 1;
final long endTime = 100;
final int uid1 = 10001;
@@ -113,7 +113,7 @@
.then((InvocationOnMock inv) -> {
NetworkTemplate template = inv.getArgument(0);
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
+ assertEquals(TEST_SUBSCRIBER_ID, template.getSubscriberId());
return history1;
});
@@ -124,13 +124,13 @@
.then((InvocationOnMock inv) -> {
NetworkTemplate template = inv.getArgument(0);
assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
+ assertEquals(TEST_SUBSCRIBER_ID, template.getSubscriberId());
return history2;
});
NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);
+ ConnectivityManager.TYPE_MOBILE, TEST_SUBSCRIBER_ID, startTime, endTime);
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
@@ -166,35 +166,30 @@
assertFalse(stats.hasNextBucket());
}
- @Test
- public void testQueryDetails_NoSubscriberId() throws RemoteException {
+ private void runQueryDetailsAndCheckTemplate(int networkType, String subscriberId,
+ NetworkTemplate expectedTemplate) throws RemoteException {
final long startTime = 1;
final long endTime = 100;
final int uid1 = 10001;
final int uid2 = 10002;
+ reset(mStatsSession);
when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });
-
- NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);
-
when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
.thenReturn(new NetworkStatsHistory(10, 0));
+ NetworkStats stats = mManager.queryDetails(
+ networkType, subscriberId, startTime, endTime);
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
+ eq(expectedTemplate),
eq(uid1), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
+ eq(expectedTemplate),
eq(uid2), eq(android.net.NetworkStats.SET_ALL),
eq(android.net.NetworkStats.TAG_NONE),
eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
@@ -202,6 +197,25 @@
assertFalse(stats.hasNextBucket());
}
+ @Test
+ public void testNetworkTemplateWhenRunningQueryDetails_NoSubscriberId() throws RemoteException {
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_MOBILE,
+ null /* subscriberId */, NetworkTemplate.buildTemplateMobileWildcard());
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
+ "" /* subscriberId */, NetworkTemplate.buildTemplateWifiWildcard());
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
+ null /* subscriberId */, NetworkTemplate.buildTemplateWifiWildcard());
+ }
+
+ @Test
+ public void testNetworkTemplateWhenRunningQueryDetails_MergedCarrierWifi()
+ throws RemoteException {
+ runQueryDetailsAndCheckTemplate(ConnectivityManager.TYPE_WIFI,
+ TEST_SUBSCRIBER_ID,
+ NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
+ TEST_SUBSCRIBER_ID));
+ }
+
private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) {
assertEquals(expected.uid, actual.getUid());
assertEquals(expected.rxBytes, actual.getRxBytes());
diff --git a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
index fc739fb..bc6dbf2 100644
--- a/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
+++ b/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
@@ -24,7 +24,9 @@
import static org.junit.Assert.fail;
import android.net.util.KeepalivePacketDataUtil;
+import android.util.Log;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,8 +40,19 @@
private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
+ private Log.TerribleFailureHandler mOriginalHandler;
+
@Before
- public void setUp() {}
+ public void setUp() {
+ // Terrible failures are logged when using deprecated methods on newer platforms
+ mOriginalHandler = Log.setWtfHandler((tag, what, sys) ->
+ Log.e(tag, "Terrible failure in test", what));
+ }
+
+ @After
+ public void tearDown() {
+ Log.setWtfHandler(mOriginalHandler);
+ }
@Test
public void testFromTcpKeepaliveStableParcelable() throws Exception {
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index a9612de..83d2e1a 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -118,6 +118,8 @@
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
+import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED;
+import static com.android.server.ConnectivityService.DEFAULT_NETWORK_PRIORITY_OEM;
import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
import static com.android.testutils.ConcurrentUtils.await;
import static com.android.testutils.ConcurrentUtils.durationOf;
@@ -456,6 +458,7 @@
private TestNetworkCallback mDefaultNetworkCallback;
private TestNetworkCallback mSystemDefaultNetworkCallback;
private TestNetworkCallback mProfileDefaultNetworkCallback;
+ private TestNetworkCallback mTestPackageDefaultNetworkCallback;
// State variables required to emulate NetworkPolicyManagerService behaviour.
private int mBlockedReasons = BLOCKED_REASON_NONE;
@@ -1523,6 +1526,8 @@
}
private static final int PRIMARY_USER = 0;
+ private static final int SECONDARY_USER = 10;
+ private static final int TERTIARY_USER = 11;
private static final UidRange PRIMARY_UIDRANGE =
UidRange.createForUser(UserHandle.of(PRIMARY_USER));
private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
@@ -1531,8 +1536,8 @@
private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
UserInfo.FLAG_PRIMARY);
private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER);
- private static final int SECONDARY_USER = 10;
private static final UserHandle SECONDARY_USER_HANDLE = new UserHandle(SECONDARY_USER);
+ private static final UserHandle TERTIARY_USER_HANDLE = new UserHandle(TERTIARY_USER);
private static final int RESTRICTED_USER = 1;
private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
@@ -10548,29 +10553,30 @@
fail("TOO_MANY_REQUESTS never thrown");
}
- private UidRange createUidRange(int userId) {
- return UidRange.createForUser(UserHandle.of(userId));
+ private void mockGetApplicationInfo(@NonNull final String packageName, final int uid) {
+ mockGetApplicationInfo(packageName, uid, PRIMARY_USER_HANDLE);
}
- private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid) {
+ private void mockGetApplicationInfo(@NonNull final String packageName, final int uid,
+ @NonNull final UserHandle user) {
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = uid;
try {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ when(mPackageManager.getApplicationInfoAsUser(eq(packageName), anyInt(), eq(user)))
.thenReturn(applicationInfo);
} catch (Exception e) {
fail(e.getMessage());
}
}
- private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
+ private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName,
+ @NonNull final UserHandle user)
throws Exception {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ when(mPackageManager.getApplicationInfoAsUser(eq(packageName), anyInt(), eq(user)))
.thenThrow(new PackageManager.NameNotFoundException(packageName));
}
- private void mockHasSystemFeature(@NonNull final String featureName,
- @NonNull final boolean hasFeature) {
+ private void mockHasSystemFeature(@NonNull final String featureName, final boolean hasFeature) {
when(mPackageManager.hasSystemFeature(eq(featureName)))
.thenReturn(hasFeature);
}
@@ -10618,8 +10624,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isListen());
@@ -10647,8 +10654,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isListen());
@@ -10673,8 +10681,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isRequest());
@@ -10696,8 +10705,9 @@
mService.new OemNetworkRequestFactory()
.createNrisFromOemNetworkPreferences(
createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
+ final NetworkRequestInfo nri = nris.iterator().next();
+ assertEquals(DEFAULT_NETWORK_PRIORITY_OEM, nri.getDefaultNetworkPriority());
+ final List<NetworkRequest> mRequests = nri.mRequests;
assertEquals(expectedNumOfNris, nris.size());
assertEquals(expectedNumOfRequests, mRequests.size());
assertTrue(mRequests.get(0).isRequest());
@@ -10764,16 +10774,18 @@
}
@Test
- public void testOemNetworkRequestFactoryMultipleUsersCorrectlySetsUids()
+ public void testOemNetworkRequestFactoryMultipleUsersSetsUids()
throws Exception {
// Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
+ final int secondUserTestPackageUid = UserHandle.getUid(SECONDARY_USER, TEST_PACKAGE_UID);
+ final int thirdUserTestPackageUid = UserHandle.getUid(TERTIARY_USER, TEST_PACKAGE_UID);
when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+ Arrays.asList(PRIMARY_USER_HANDLE, SECONDARY_USER_HANDLE, TERTIARY_USER_HANDLE));
- // Arrange PackageManager mocks
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+ // Arrange PackageManager mocks testing for users who have and don't have a package.
+ mockGetApplicationInfoThrowsNameNotFound(TEST_PACKAGE_NAME, PRIMARY_USER_HANDLE);
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, SECONDARY_USER_HANDLE);
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, thirdUserTestPackageUid, TERTIARY_USER_HANDLE);
// Build OemNetworkPreferences object
final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
@@ -10787,8 +10799,8 @@
mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
pref));
- // UIDs for all users and all managed packages should be present.
- // Two users each with two packages.
+ // UIDs for users with installed packages should be present.
+ // Three users exist, but only two have the test package installed.
final int expectedUidSize = 2;
final List<Range<Integer>> uids =
new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
@@ -10796,11 +10808,10 @@
// Sort by uid to access nris by index
uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(0).getLower());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(0).getUpper());
+ assertEquals(thirdUserTestPackageUid, (int) uids.get(1).getLower());
+ assertEquals(thirdUserTestPackageUid, (int) uids.get(1).getUpper());
}
@Test
@@ -10961,16 +10972,24 @@
}
private void registerDefaultNetworkCallbacks() {
+ if (mSystemDefaultNetworkCallback != null || mDefaultNetworkCallback != null
+ || mProfileDefaultNetworkCallback != null
+ || mTestPackageDefaultNetworkCallback != null) {
+ throw new IllegalStateException("Default network callbacks already registered");
+ }
+
// Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
mSystemDefaultNetworkCallback = new TestNetworkCallback();
mDefaultNetworkCallback = new TestNetworkCallback();
mProfileDefaultNetworkCallback = new TestNetworkCallback();
+ mTestPackageDefaultNetworkCallback = new TestNetworkCallback();
mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
new Handler(ConnectivityThread.getInstanceLooper()));
mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
TEST_WORK_PROFILE_APP_UID);
+ registerDefaultNetworkCallbackAsUid(mTestPackageDefaultNetworkCallback, TEST_PACKAGE_UID);
// TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
}
@@ -10985,6 +11004,9 @@
if (null != mProfileDefaultNetworkCallback) {
mCm.unregisterNetworkCallback(mProfileDefaultNetworkCallback);
}
+ if (null != mTestPackageDefaultNetworkCallback) {
+ mCm.unregisterNetworkCallback(mTestPackageDefaultNetworkCallback);
+ }
}
private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@@ -11601,6 +11623,7 @@
final UidRangeParcel[] uidRanges =
toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, secondUserHandle);
setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
// Verify the starting state. No networks should be connected.
@@ -11643,6 +11666,7 @@
final UidRangeParcel[] uidRangesBothUsers =
toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, secondUserTestPackageUid, secondUserHandle);
setupSetOemNetworkPreferenceForPreferenceTest(
networkPref, uidRangesSingleUser, TEST_PACKAGE_NAME);
@@ -11699,7 +11723,7 @@
final UidRangeParcel[] uidRangesSinglePackage =
toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall, PRIMARY_USER_HANDLE);
setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
@@ -11733,7 +11757,7 @@
false /* shouldDestroyNetwork */);
// Set the system to no longer recognize the package to be installed
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall, PRIMARY_USER_HANDLE);
// Send a broadcast indicating a package was removed.
final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
@@ -12874,6 +12898,8 @@
assertEquals(1, nris.size());
assertTrue(nri.isMultilayerRequest());
assertEquals(nri.getUids(), uidRangesForUids(uids));
+ assertEquals(DEFAULT_NETWORK_PRIORITY_MOBILE_DATA_PREFERRED,
+ nri.getDefaultNetworkPriority());
}
/**
@@ -12906,9 +12932,11 @@
@Test
public void testMobileDataPreferredUidsChanged() throws Exception {
final InOrder inorder = inOrder(mMockNetd);
+ registerDefaultNetworkCallbacks();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- waitForIdle();
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
final int cellNetId = mCellNetworkAgent.getNetwork().netId;
inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
@@ -12919,12 +12947,15 @@
inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ // Set MOBILE_DATA_PREFERRED_UIDS setting and verify that net id and uid ranges send to netd
final Set<Integer> uids1 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
final UidRangeParcel[] uidRanges1 = toUidRangeStableParcels(uidRangesForUids(uids1));
setAndUpdateMobileDataPreferredUids(uids1);
inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges1);
inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ // Set MOBILE_DATA_PREFERRED_UIDS setting again and verify that old rules are removed and
+ // new rules are added.
final Set<Integer> uids2 = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID),
PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID2),
SECONDARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
@@ -12932,5 +12963,170 @@
setAndUpdateMobileDataPreferredUids(uids2);
inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(cellNetId, uidRanges1);
inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges2);
+
+ // Clear MOBILE_DATA_PREFERRED_UIDS setting again and verify that old rules are removed and
+ // new rules are not added.
+ final Set<Integer> uids3 = Set.of();
+ final UidRangeParcel[] uidRanges3 = toUidRangeStableParcels(uidRangesForUids(uids3));
+ setAndUpdateMobileDataPreferredUids(uids3);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(cellNetId, uidRanges2);
+ inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ }
+
+ /**
+ * Make sure mobile data preferred uids feature behaves as expected when the mobile network
+ * goes up and down while the uids is set. Make sure they behave as expected whether
+ * there is a general default network or not.
+ */
+ @Test
+ public void testMobileDataPreferenceForMobileNetworkUpDown() throws Exception {
+ final InOrder inorder = inOrder(mMockNetd);
+ // File a request for cell to ensure it doesn't go down.
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ mCm.requestNetwork(cellRequest, cellNetworkCallback);
+ cellNetworkCallback.assertNoCallback();
+
+ registerDefaultNetworkCallbacks();
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+ final int wifiNetId = mWiFiNetworkAgent.getNetwork().netId;
+ inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+ wifiNetId, INetd.PERMISSION_NONE));
+
+ // Initial mobile data preferred uids status.
+ setAndUpdateMobileDataPreferredUids(Set.of());
+ inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+
+ // Set MOBILE_DATA_PREFERRED_UIDS setting and verify that wifi net id and uid ranges send to
+ // netd.
+ final Set<Integer> uids = Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID));
+ final UidRangeParcel[] uidRanges = toUidRangeStableParcels(uidRangesForUids(uids));
+ setAndUpdateMobileDataPreferredUids(uids);
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(wifiNetId, uidRanges);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+
+ // Cellular network connected. mTestPackageDefaultNetworkCallback should receive
+ // callback with cellular network and net id and uid ranges should be updated to netd.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.assertNoCallback();
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+ final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+ inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+ cellNetId, INetd.PERMISSION_NONE));
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId, uidRanges);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(wifiNetId, uidRanges);
+
+ // Cellular network disconnected. mTestPackageDefaultNetworkCallback should receive
+ // callback with wifi network from fallback request.
+ mCellNetworkAgent.disconnect();
+ mDefaultNetworkCallback.assertNoCallback();
+ cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(wifiNetId, uidRanges);
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd).networkDestroy(cellNetId);
+
+ // Cellular network comes back. mTestPackageDefaultNetworkCallback should receive
+ // callback with cellular network.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.assertNoCallback();
+ mTestPackageDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+
+ final int cellNetId2 = mCellNetworkAgent.getNetwork().netId;
+ inorder.verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(
+ cellNetId2, INetd.PERMISSION_NONE));
+ inorder.verify(mMockNetd, times(1)).networkAddUidRanges(cellNetId2, uidRanges);
+ inorder.verify(mMockNetd, times(1)).networkRemoveUidRanges(wifiNetId, uidRanges);
+
+ // Wifi network disconnected. mTestPackageDefaultNetworkCallback should not receive
+ // any callback.
+ mWiFiNetworkAgent.disconnect();
+ mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ mTestPackageDefaultNetworkCallback.assertNoCallback();
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(TEST_PACKAGE_UID));
+ waitForIdle();
+ inorder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd, never()).networkRemoveUidRanges(anyInt(), any());
+ inorder.verify(mMockNetd).networkDestroy(wifiNetId);
+
+ mCm.unregisterNetworkCallback(cellNetworkCallback);
+ }
+
+ @Test
+ public void testSetMobileDataPreferredUids_noIssueToFactory() throws Exception {
+ // First set mobile data preferred uid to create a multi-layer requests: 1. listen for
+ // cellular, 2. track the default network for fallback.
+ setAndUpdateMobileDataPreferredUids(
+ Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID)));
+
+ final HandlerThread handlerThread = new HandlerThread("MockFactory");
+ handlerThread.start();
+ NetworkCapabilities internetFilter = new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ final MockNetworkFactory internetFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
+ internetFactory.setScoreFilter(40);
+
+ try {
+ internetFactory.register();
+ // Default internet request only. The first request is listen for cellular network,
+ // which is never sent to factories (it's a LISTEN, not requestable). The second
+ // fallback request is TRACK_DEFAULT which is also not sent to factories.
+ internetFactory.expectRequestAdds(1);
+ internetFactory.assertRequestCountEquals(1);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ // The internet factory however is outscored, and should lose its requests.
+ internetFactory.expectRequestRemove();
+ internetFactory.assertRequestCountEquals(0);
+
+ mCellNetworkAgent.disconnect();
+ // The network satisfying the default internet request has disconnected, so the
+ // internetFactory sees the default request again.
+ internetFactory.expectRequestAdds(1);
+ internetFactory.assertRequestCountEquals(1);
+ } finally {
+ internetFactory.terminate();
+ handlerThread.quitSafely();
+ }
+ }
+
+ /**
+ * Validate request counts are counted accurately on MOBILE_DATA_PREFERRED_UIDS change
+ * on set/replace.
+ */
+ @Test
+ public void testMobileDataPreferredUidsChangedCountsRequestsCorrectlyOnSet() throws Exception {
+ ConnectivitySettingsManager.setMobileDataPreferredUids(mServiceContext,
+ Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID)));
+ testRequestCountLimits(() -> {
+ // Set initially to test the limit prior to having existing requests.
+ mService.updateMobileDataPreferredUids();
+ waitForIdle();
+
+ // re-set so as to test the limit as part of replacing existing requests.
+ mService.updateMobileDataPreferredUids();
+ waitForIdle();
+ });
}
}
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index a90fa68..20be5f4 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -57,6 +57,7 @@
public class NsdServiceTest {
static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
+ private static final long CLEANUP_DELAY_MS = 500;
long mTimeoutMs = 100; // non-final so that tests can adjust the value.
@@ -86,20 +87,27 @@
}
@Test
- public void testClientsCanConnectAndDisconnect() {
+ public void testNoDaemonStartedWhenClientsConnect() {
when(mSettings.isEnabled()).thenReturn(true);
NsdService service = makeService();
+ // Creating an NsdManager will not cause any cmds executed, which means
+ // no daemon is started.
NsdManager client1 = connectClient(service);
- verify(mDaemon, timeout(100).times(1)).start();
+ verify(mDaemon, never()).execute(any());
+ // Creating another NsdManager will not cause any cmds executed.
NsdManager client2 = connectClient(service);
+ verify(mDaemon, never()).execute(any());
client1.disconnect();
- client2.disconnect();
+ // Still 1 client remains, daemon shouldn't be stopped.
+ verify(mDaemon, never()).maybeStop();
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
+ client2.disconnect();
+ // All clients are disconnected, stop the daemon after CLEANUP_DELAY_MS.
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
client1.disconnect();
client2.disconnect();
@@ -113,7 +121,8 @@
NsdService service = makeService();
NsdManager client = connectClient(service);
- verify(mDaemon, timeout(100).times(1)).start();
+ verify(mDaemon, never()).maybeStart();
+ verify(mDaemon, never()).execute(any());
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
request.setPort(2201);
@@ -121,21 +130,24 @@
// Client registration request
NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
client.registerService(request, PROTOCOL, listener1);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
verifyDaemonCommand("register 2 a_name a_type 2201");
// Client discovery request
NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
client.discoverServices("a_type", PROTOCOL, listener2);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
verifyDaemonCommand("discover 3 a_type");
// Client resolve request
NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
client.resolveService(request, listener3);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
verifyDaemonCommand("resolve 4 a_name a_type local.");
- // Client disconnects
+ // Client disconnects, stop the daemon after CLEANUP_DELAY_MS.
client.disconnect();
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
// checks that request are cleaned
verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
@@ -143,12 +155,38 @@
client.disconnect();
}
+ @Test
+ public void testCleanupDelayNoRequestActive() {
+ when(mSettings.isEnabled()).thenReturn(true);
+ when(mDaemon.execute(any())).thenReturn(true);
+
+ NsdService service = makeService();
+ NsdManager client = connectClient(service);
+
+ NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+ request.setPort(2201);
+ NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
+ client.registerService(request, PROTOCOL, listener1);
+ verify(mDaemon, timeout(mTimeoutMs).times(1)).maybeStart();
+ verifyDaemonCommand("register 2 a_name a_type 2201");
+
+ client.unregisterService(listener1);
+ verifyDaemonCommand("stop-register 2");
+
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
+ reset(mDaemon);
+ client.disconnect();
+ // Client disconnects, after CLEANUP_DELAY_MS, maybeStop the daemon.
+ verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
+ }
+
NsdService makeService() {
DaemonConnectionSupplier supplier = (callback) -> {
mDaemonCallback = callback;
return mDaemon;
};
- NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
+ NsdService service = new NsdService(mContext, mSettings,
+ mHandler, supplier, CLEANUP_DELAY_MS);
verify(mDaemon, never()).execute(any(String.class));
return service;
}
@@ -157,6 +195,13 @@
return new NsdManager(mContext, service);
}
+ void verifyDelayMaybeStopDaemon(long cleanupDelayMs) {
+ // Stop daemon shouldn't be called immediately.
+ verify(mDaemon, timeout(mTimeoutMs).times(0)).maybeStop();
+ // Clean up the daemon after CLEANUP_DELAY_MS.
+ verify(mDaemon, timeout(cleanupDelayMs + mTimeoutMs)).maybeStop();
+ }
+
void verifyDaemonCommands(String... wants) {
verifyDaemonCommand(String.join(" ", wants), wants.length);
}