Merge changes from topic 'network_specifier'
* changes:
[CM] Unhide the NetworkSpecifier as object API
Make the NetworkSpecifier a class instead of a string.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index e163365..2a985e7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -88,6 +88,13 @@
* sent as an extra; it should be consulted to see what kind of
* connectivity event occurred.
* <p/>
+ * Apps targeting Android 7.0 (API level 24) and higher do not receive this
+ * broadcast if they declare the broadcast receiver in their manifest. Apps
+ * will still receive broadcasts if they register their
+ * {@link android.content.BroadcastReceiver} with
+ * {@link android.content.Context#registerReceiver Context.registerReceiver()}
+ * and that context is still valid.
+ * <p/>
* If this is a connection that was the result of failing over from a
* disconnected network, then the FAILOVER_CONNECTION boolean extra is
* set to true.
@@ -3400,6 +3407,75 @@
}
/**
+ * It is acceptable to briefly use multipath data to provide seamless connectivity for
+ * time-sensitive user-facing operations when the system default network is temporarily
+ * unresponsive. The amount of data should be limited (less than one megabyte), and the
+ * operation should be infrequent to ensure that data usage is limited.
+ *
+ * An example of such an operation might be a time-sensitive foreground activity, such as a
+ * voice command, that the user is performing while walking out of range of a Wi-Fi network.
+ */
+ public static final int MULTIPATH_PREFERENCE_HANDOVER = 1 << 0;
+
+ /**
+ * It is acceptable to use small amounts of multipath data on an ongoing basis to provide
+ * a backup channel for traffic that is primarily going over another network.
+ *
+ * An example might be maintaining backup connections to peers or servers for the purpose of
+ * fast fallback if the default network is temporarily unresponsive or disconnects. The traffic
+ * on backup paths should be negligible compared to the traffic on the main path.
+ */
+ public static final int MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1;
+
+ /**
+ * It is acceptable to use metered data to improve network latency and performance.
+ */
+ public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2;
+
+ /**
+ * Return value to use for unmetered networks. On such networks we currently set all the flags
+ * to true.
+ * @hide
+ */
+ public static final int MULTIPATH_PREFERENCE_UNMETERED =
+ MULTIPATH_PREFERENCE_HANDOVER |
+ MULTIPATH_PREFERENCE_RELIABILITY |
+ MULTIPATH_PREFERENCE_PERFORMANCE;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ MULTIPATH_PREFERENCE_HANDOVER,
+ MULTIPATH_PREFERENCE_RELIABILITY,
+ MULTIPATH_PREFERENCE_PERFORMANCE,
+ })
+ public @interface MultipathPreference {
+ }
+
+ /**
+ * Provides a hint to the calling application on whether it is desirable to use the
+ * multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.)
+ * for multipath data transfer on this network when it is not the system default network.
+ * Applications desiring to use multipath network protocols should call this method before
+ * each such operation.
+ * <p>
+ * This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @param network The network on which the application desires to use multipath data.
+ * If {@code null}, this method will return the a preference that will generally
+ * apply to metered networks.
+ * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
+ */
+ public @MultipathPreference int getMultipathPreference(Network network) {
+ try {
+ return mService.getMultipathPreference(network);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resets all connectivity manager settings back to factory defaults.
* @hide
*/
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b123c28..425e494 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -161,6 +161,8 @@
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
void setAvoidUnvalidated(in Network network);
+ int getMultipathPreference(in Network Network);
+
int getRestoreDefaultNetworkDelay(int networkType);
boolean addVpnAddress(String address, int prefixLength);
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
index 4f2387d..fcc6389 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -18,14 +18,14 @@
import android.net.IpPrefix;
import android.os.Parcel;
+import static android.test.MoreAsserts.assertNotEqual;
import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.junit.Assert.assertArrayEquals;
import java.net.InetAddress;
import java.util.Random;
import junit.framework.TestCase;
-import static android.test.MoreAsserts.assertNotEqual;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
public class IpPrefixTest extends TestCase {
@@ -242,42 +242,25 @@
@SmallTest
public void testHashCode() {
- IpPrefix p = new IpPrefix(new byte[4], 0);
+ IpPrefix p;
+ int oldCode = -1;
Random random = new Random();
for (int i = 0; i < 100; i++) {
- final IpPrefix oldP = p;
if (random.nextBoolean()) {
// IPv4.
byte[] b = new byte[4];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(33));
+ assertNotEqual(oldCode, p.hashCode());
+ oldCode = p.hashCode();
} else {
// IPv6.
byte[] b = new byte[16];
random.nextBytes(b);
p = new IpPrefix(b, random.nextInt(129));
+ assertNotEqual(oldCode, p.hashCode());
+ oldCode = p.hashCode();
}
- if (p.equals(oldP)) {
- assertEquals(p.hashCode(), oldP.hashCode());
- }
- if (p.hashCode() != oldP.hashCode()) {
- assertNotEqual(p, oldP);
- }
- }
- }
-
- @SmallTest
- public void testHashCodeIsNotConstant() {
- IpPrefix[] prefixes = {
- new IpPrefix("2001:db8:f00::ace:d00d/127"),
- new IpPrefix("192.0.2.0/23"),
- new IpPrefix("::/0"),
- new IpPrefix("0.0.0.0/0"),
- };
- for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
- }
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 079b670..4f8ff1d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1304,13 +1304,16 @@
@Override
public LinkProperties getLinkProperties(Network network) {
enforceAccessPermission();
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai != null) {
- synchronized (nai) {
- return new LinkProperties(nai.linkProperties);
- }
+ return getLinkProperties(getNetworkAgentInfoForNetwork(network));
+ }
+
+ private LinkProperties getLinkProperties(NetworkAgentInfo nai) {
+ if (nai == null) {
+ return null;
}
- return null;
+ synchronized (nai) {
+ return new LinkProperties(nai.linkProperties);
+ }
}
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
@@ -2836,6 +2839,18 @@
}
}
+ @Override
+ public int getMultipathPreference(Network network) {
+ enforceAccessPermission();
+
+ NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai != null && !nai.networkInfo.isMetered()) {
+ return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
+ }
+
+ return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
+ }
+
private class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
@@ -3134,7 +3149,8 @@
enforceAccessPermission();
enforceInternetPermission();
- NetworkAgentInfo nai;
+ // TODO: execute this logic on ConnectivityService handler.
+ final NetworkAgentInfo nai;
if (network == null) {
nai = getDefaultNetwork();
} else {
@@ -3145,21 +3161,24 @@
return;
}
// Revalidate if the app report does not match our current validated state.
- if (hasConnectivity == nai.lastValidated) return;
+ if (hasConnectivity == nai.lastValidated) {
+ return;
+ }
final int uid = Binder.getCallingUid();
if (DBG) {
log("reportNetworkConnectivity(" + nai.network.netId + ", " + hasConnectivity +
") by " + uid);
}
- synchronized (nai) {
- // Validating a network that has not yet connected could result in a call to
- // rematchNetworkAndRequests() which is not meant to work on such networks.
- if (!nai.everConnected) return;
-
- if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) return;
-
- nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
+ // Validating a network that has not yet connected could result in a call to
+ // rematchNetworkAndRequests() which is not meant to work on such networks.
+ if (!nai.everConnected) {
+ return;
}
+ LinkProperties lp = getLinkProperties(nai);
+ if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
+ return;
+ }
+ nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
}
private ProxyInfo getDefaultProxy() {
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 9ffa40b..4ff6657 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -19,7 +19,6 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.widget.Toast;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -27,18 +26,40 @@
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.Slog;
-import com.android.internal.annotations.VisibleForTesting;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.widget.Toast;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
-import static android.net.NetworkCapabilities.*;
-
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
public class NetworkNotificationManager {
- public static enum NotificationType { SIGN_IN, NO_INTERNET, LOST_INTERNET, NETWORK_SWITCH };
+ public static enum NotificationType {
+ LOST_INTERNET(MetricsEvent.NOTIFICATION_NETWORK_LOST_INTERNET),
+ NETWORK_SWITCH(MetricsEvent.NOTIFICATION_NETWORK_SWITCH),
+ NO_INTERNET(MetricsEvent.NOTIFICATION_NETWORK_NO_INTERNET),
+ SIGN_IN(MetricsEvent.NOTIFICATION_NETWORK_SIGN_IN);
- @VisibleForTesting
- static final String NOTIFICATION_ID = "Connectivity.Notification";
+ public final int eventId;
+
+ NotificationType(int eventId) {
+ this.eventId = eventId;
+ Holder.sIdToTypeMap.put(eventId, this);
+ }
+
+ private static class Holder {
+ private static SparseArray<NotificationType> sIdToTypeMap = new SparseArray<>();
+ }
+
+ public static NotificationType getFromId(int id) {
+ return Holder.sIdToTypeMap.get(id);
+ }
+ };
private static final String TAG = NetworkNotificationManager.class.getSimpleName();
private static final boolean DBG = true;
@@ -47,11 +68,14 @@
private final Context mContext;
private final TelephonyManager mTelephonyManager;
private final NotificationManager mNotificationManager;
+ // Tracks the types of notifications managed by this instance, from creation to cancellation.
+ private final SparseIntArray mNotificationTypeMap;
public NetworkNotificationManager(Context c, TelephonyManager t, NotificationManager n) {
mContext = c;
mTelephonyManager = t;
mNotificationManager = n;
+ mNotificationTypeMap = new SparseIntArray();
}
// TODO: deal more gracefully with multi-transport networks.
@@ -101,8 +125,10 @@
*/
public void showNotification(int id, NotificationType notifyType, NetworkAgentInfo nai,
NetworkAgentInfo switchToNai, PendingIntent intent, boolean highPriority) {
- int transportType;
- String extraInfo;
+ final String tag = tagFor(id);
+ final int eventId = notifyType.eventId;
+ final int transportType;
+ final String extraInfo;
if (nai != null) {
transportType = getFirstTransportType(nai);
extraInfo = nai.networkInfo.getExtraInfo();
@@ -115,9 +141,10 @@
}
if (DBG) {
- Slog.d(TAG, "showNotification id=" + id + " " + notifyType
- + " transportType=" + getTransportName(transportType)
- + " extraInfo=" + extraInfo + " highPriority=" + highPriority);
+ Slog.d(TAG, String.format(
+ "showNotification tag=%s event=%s transport=%s extraInfo=%s highPrioriy=%s",
+ tag, nameOf(eventId), getTransportName(transportType), extraInfo,
+ highPriority));
}
Resources r = Resources.getSystem();
@@ -155,7 +182,7 @@
details = r.getString(R.string.network_switch_metered_detail, toTransport,
fromTransport);
} else {
- Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network transport "
+ Slog.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
+ getTransportName(transportType));
return;
}
@@ -185,22 +212,31 @@
Notification notification = builder.build();
+ mNotificationTypeMap.put(id, eventId);
try {
- mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
+ mNotificationManager.notifyAsUser(tag, eventId, notification, UserHandle.ALL);
} catch (NullPointerException npe) {
Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
}
}
public void clearNotification(int id) {
+ if (mNotificationTypeMap.indexOfKey(id) < 0) {
+ return;
+ }
+ final String tag = tagFor(id);
+ final int eventId = mNotificationTypeMap.get(id);
if (DBG) {
- Slog.d(TAG, "clearNotification id=" + id);
+ Slog.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
+ nameOf(eventId)));
}
try {
- mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(tag, eventId, UserHandle.ALL);
} catch (NullPointerException npe) {
- Slog.d(TAG, "setNotificationVisible: cancel notificationManager error", npe);
+ Slog.d(TAG, String.format(
+ "failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe);
}
+ mNotificationTypeMap.delete(id);
}
/**
@@ -223,4 +259,15 @@
R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
}
+
+ @VisibleForTesting
+ static String tagFor(int id) {
+ return String.format("ConnectivityNotification:%d", id);
+ }
+
+ @VisibleForTesting
+ static String nameOf(int eventId) {
+ NotificationType t = NotificationType.getFromId(eventId);
+ return (t != null) ? t.name() : "UNKNOWN";
+ }
}
diff --git a/services/net/java/android/net/util/MultinetworkPolicyTracker.java b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
index ebd131b..424e40d 100644
--- a/services/net/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
@@ -29,10 +30,14 @@
import android.provider.Settings;
import android.util.Slog;
+import java.util.Arrays;
+import java.util.List;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.R;
import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
+import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
/**
* A class to encapsulate management of the "Smart Networking" capability of
@@ -57,12 +62,13 @@
private final Context mContext;
private final Handler mHandler;
private final Runnable mReevaluateRunnable;
- private final Uri mAvoidBadWifiUri;
+ private final List<Uri> mSettingsUris;
private final ContentResolver mResolver;
private final SettingObserver mSettingObserver;
private final BroadcastReceiver mBroadcastReceiver;
private volatile boolean mAvoidBadWifi = true;
+ private volatile int mMeteredMultipathPreference;
public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
@@ -72,9 +78,14 @@
mContext = ctx;
mHandler = handler;
mReevaluateRunnable = () -> {
- if (updateAvoidBadWifi() && avoidBadWifiCallback != null) avoidBadWifiCallback.run();
+ if (updateAvoidBadWifi() && avoidBadWifiCallback != null) {
+ avoidBadWifiCallback.run();
+ }
+ updateMeteredMultipathPreference();
};
- mAvoidBadWifiUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
+ mSettingsUris = Arrays.asList(
+ Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
+ Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() {
@@ -85,10 +96,13 @@
};
updateAvoidBadWifi();
+ updateMeteredMultipathPreference();
}
public void start() {
- mResolver.registerContentObserver(mAvoidBadWifiUri, false, mSettingObserver);
+ for (Uri uri : mSettingsUris) {
+ mResolver.registerContentObserver(uri, false, mSettingObserver);
+ }
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -108,6 +122,10 @@
return mAvoidBadWifi;
}
+ public int getMeteredMultipathPreference() {
+ return mMeteredMultipathPreference;
+ }
+
/**
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
@@ -138,6 +156,23 @@
return mAvoidBadWifi != prev;
}
+ /**
+ * The default (device and carrier-dependent) value for metered multipath preference.
+ */
+ public int configMeteredMultipathPreference() {
+ return mContext.getResources().getInteger(
+ R.integer.config_networkMeteredMultipathPreference);
+ }
+
+ public void updateMeteredMultipathPreference() {
+ String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
+ try {
+ mMeteredMultipathPreference = Integer.parseInt(setting);
+ } catch (NumberFormatException e) {
+ mMeteredMultipathPreference = configMeteredMultipathPreference();
+ }
+ }
+
private class SettingObserver extends ContentObserver {
public SettingObserver() {
super(null);
@@ -150,7 +185,9 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (!mAvoidBadWifiUri.equals(uri)) return;
+ if (!mSettingsUris.contains(uri)) {
+ Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+ }
reevaluate();
}
}
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/services/tests/servicestests/src/com/android/server/connectivity/NetworkNotificationManagerTest.java
similarity index 89%
rename from tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
rename to services/tests/servicestests/src/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 813e928..21c2de7 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -48,8 +48,6 @@
public class NetworkNotificationManagerTest extends TestCase {
- static final String NOTIFICATION_ID = NetworkNotificationManager.NOTIFICATION_ID;
-
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
static {
@@ -82,6 +80,7 @@
when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm);
when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
+ when(mNetworkInfo.getExtraInfo()).thenReturn("extra");
when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
@@ -108,11 +107,11 @@
}
for (int i = 0; i < ids.size(); i++) {
- final int expectedId = NETWORK_ID_BASE + i;
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(NOTIFICATION_ID), eq(expectedId), any(), any());
- verify(mNotificationManager, times(1))
- .cancelAsUser(eq(NOTIFICATION_ID), eq(expectedId), any());
+ final int id = ids.get(i);
+ final int eventId = types.get(i).eventId;
+ final String tag = NetworkNotificationManager.tagFor(id);
+ verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
+ verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(eventId), any());
}
}
@@ -125,8 +124,9 @@
mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(NOTIFICATION_ID), eq(102), any(), any());
+ final int eventId = NO_INTERNET.eventId;
+ final String tag = NetworkNotificationManager.tagFor(102);
+ verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
}
@SmallTest
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 51c8907..1be8d5e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -638,6 +638,7 @@
private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
public volatile boolean configRestrictsAvoidBadWifi;
+ public volatile int configMeteredMultipathPreference;
public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
super(c, h, r);
@@ -647,6 +648,11 @@
public boolean configRestrictsAvoidBadWifi() {
return configRestrictsAvoidBadWifi;
}
+
+ @Override
+ public int configMeteredMultipathPreference() {
+ return configMeteredMultipathPreference;
+ }
}
private class WrappedConnectivityService extends ConnectivityService {
@@ -2496,6 +2502,26 @@
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @SmallTest
+ public void testMeteredMultipathPreferenceSetting() throws Exception {
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
+ final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+
+ for (int config : Arrays.asList(0, 3, 2)) {
+ for (String setting: Arrays.asList(null, "0", "2", "1")) {
+ tracker.configMeteredMultipathPreference = config;
+ Settings.Global.putString(cr, settingName, setting);
+ tracker.reevaluate();
+ mService.waitForIdle();
+
+ final int expected = (setting != null) ? Integer.parseInt(setting) : config;
+ String msg = String.format("config=%d, setting=%s", config, setting);
+ assertEquals(msg, expected, mCm.getMultipathPreference(null));
+ }
+ }
+ }
+
/**
* Validate that a satisfied network request does not trigger onUnavailable() once the
* time-out period expires.
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index 84f0f90..8c16dbb 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -16,6 +16,17 @@
package com.android.server.connectivity;
+import static com.android.server.connectivity.MetricsTestUtil.aBool;
+import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
+import static com.android.server.connectivity.MetricsTestUtil.aLong;
+import static com.android.server.connectivity.MetricsTestUtil.aString;
+import static com.android.server.connectivity.MetricsTestUtil.aType;
+import static com.android.server.connectivity.MetricsTestUtil.anInt;
+import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
+import static com.android.server.connectivity.MetricsTestUtil.b;
+import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
+import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
+
import android.net.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
@@ -28,24 +39,13 @@
import android.net.metrics.NetworkEvent;
import android.net.metrics.RaEvent;
import android.net.metrics.ValidationProbeEvent;
-import com.google.protobuf.nano.MessageNano;
+import android.test.suitebuilder.annotation.SmallTest;
import java.util.Arrays;
import junit.framework.TestCase;
-import static com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityLog;
-import static com.android.server.connectivity.MetricsTestUtil.aBool;
-import static com.android.server.connectivity.MetricsTestUtil.aByteArray;
-import static com.android.server.connectivity.MetricsTestUtil.aLong;
-import static com.android.server.connectivity.MetricsTestUtil.aString;
-import static com.android.server.connectivity.MetricsTestUtil.aType;
-import static com.android.server.connectivity.MetricsTestUtil.anInt;
-import static com.android.server.connectivity.MetricsTestUtil.anIntArray;
-import static com.android.server.connectivity.MetricsTestUtil.b;
-import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
-import static com.android.server.connectivity.MetricsTestUtil.ipEv;
-
public class IpConnectivityEventBuilderTest extends TestCase {
+ @SmallTest
public void testDefaultNetworkEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(DefaultNetworkEvent.class),
@@ -71,12 +71,14 @@
" transport_types: 3",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testDhcpClientEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(DhcpClientEvent.class),
@@ -94,12 +96,14 @@
" state_transition: \"SomeState\"",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testDhcpErrorEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(DhcpErrorEvent.class),
@@ -116,12 +120,14 @@
" state_transition: \"\"",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testDnsEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(DnsEvent.class),
@@ -163,12 +169,14 @@
" return_codes: 178",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testIpManagerEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpManagerEvent.class),
@@ -185,12 +193,14 @@
" latency_ms: 5678",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testIpReachabilityEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(IpReachabilityEvent.class),
@@ -205,12 +215,14 @@
" if_name: \"wlan0\"",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testNetworkEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(NetworkEvent.class),
@@ -229,12 +241,14 @@
" >",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testValidationProbeEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(ValidationProbeEvent.class),
@@ -247,6 +261,7 @@
"dropped_events: 0",
"events <",
" time_ms: 1",
+ " transport: 0",
" validation_probe_event <",
" latency_ms: 40730",
" network_id <",
@@ -261,6 +276,7 @@
verifySerialization(want, ev);
}
+ @SmallTest
public void testApfProgramEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(ApfProgramEvent.class),
@@ -282,12 +298,14 @@
" program_length: 2048",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testApfStatsSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(ApfStats.class),
@@ -314,12 +332,14 @@
" zero_lifetime_ras: 1",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
verifySerialization(want, ev);
}
+ @SmallTest
public void testRaEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(RaEvent.class),
@@ -342,6 +362,7 @@
" router_lifetime: 2000",
" >",
" time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -350,9 +371,9 @@
static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
try {
- byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
- IpConnectivityLog log = new IpConnectivityLog();
- MessageNano.mergeFrom(log, got);
+ byte[] got = IpConnectivityEventBuilder.serialize(0,
+ IpConnectivityEventBuilder.toProto(Arrays.asList(input)));
+ IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
assertEquals(want, log.toString());
} catch (Exception e) {
fail(e.toString());
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index aa491bb..9a33cde 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -16,6 +16,9 @@
package com.android.server.connectivity;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
import android.content.Context;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
@@ -29,9 +32,9 @@
import android.net.metrics.RaEvent;
import android.net.metrics.ValidationProbeEvent;
import android.os.Parcelable;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.Base64;
import com.android.server.connectivity.metrics.IpConnectivityLogClass;
-import com.google.protobuf.nano.MessageNano;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
@@ -43,10 +46,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
public class IpConnectivityMetricsTest extends TestCase {
static final IpReachabilityEvent FAKE_EV =
new IpReachabilityEvent("wlan0", IpReachabilityEvent.NUD_FAILED);
@@ -61,6 +60,7 @@
mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
}
+ @SmallTest
public void testLoggingEvents() throws Exception {
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
@@ -74,6 +74,7 @@
assertEventsEqual(expectedEvent(3), got.get(2));
}
+ @SmallTest
public void testLoggingEventsWithMultipleCallers() throws Exception {
IpConnectivityLog logger = new IpConnectivityLog(mMockService);
@@ -101,6 +102,7 @@
}
}
+ @SmallTest
public void testBufferFlushing() {
String output1 = getdump("flush");
assertEquals("", output1);
@@ -113,6 +115,7 @@
assertEquals("", output3);
}
+ @SmallTest
public void testRateLimiting() {
final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
final ApfProgramEvent ev = new ApfProgramEvent(0, 0, 0, 0, 0);
@@ -134,6 +137,7 @@
assertEquals("", output2);
}
+ @SmallTest
public void testEndToEndLogging() {
IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
@@ -159,6 +163,7 @@
" if_name: \"wlan0\"",
" >",
" time_ms: 100",
+ " transport: 0",
">",
"events <",
" dhcp_event <",
@@ -168,6 +173,7 @@
" state_transition: \"SomeState\"",
" >",
" time_ms: 200",
+ " transport: 0",
">",
"events <",
" default_network_event <",
@@ -183,6 +189,7 @@
" transport_types: 3",
" >",
" time_ms: 300",
+ " transport: 0",
">",
"events <",
" ip_provisioning_event <",
@@ -191,9 +198,11 @@
" latency_ms: 5678",
" >",
" time_ms: 400",
+ " transport: 0",
">",
"events <",
" time_ms: 500",
+ " transport: 0",
" validation_probe_event <",
" latency_ms: 40730",
" network_id <",
@@ -215,6 +224,7 @@
" zero_lifetime_ras: 1",
" >",
" time_ms: 600",
+ " transport: 0",
">",
"events <",
" ra_event <",
@@ -226,6 +236,7 @@
" router_lifetime: 2000",
" >",
" time_ms: 700",
+ " transport: 0",
">",
"version: 2");
@@ -254,8 +265,7 @@
try {
byte[] got = Base64.decode(output, Base64.DEFAULT);
IpConnectivityLogClass.IpConnectivityLog log =
- new IpConnectivityLogClass.IpConnectivityLog();
- MessageNano.mergeFrom(log, got);
+ IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
assertEquals(want, log.toString());
} catch (Exception e) {
fail(e.toString());
@@ -283,10 +293,5 @@
}
static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
- new Comparator<ConnectivityMetricsEvent>() {
- @Override
- public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
- return (int) (ev1.timestamp - ev2.timestamp);
- }
- };
+ Comparator.comparingLong((ev) -> ev.timestamp);
}
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 2bb62bb..6c8babb 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -16,25 +16,34 @@
package com.android.server.connectivity;
-import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.metrics.DnsEvent;
import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
import android.os.RemoteException;
+import android.system.OsConstants;
import android.test.suitebuilder.annotation.SmallTest;
-
+import com.android.server.connectivity.metrics.IpConnectivityLogClass.IpConnectivityEvent;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.stream.IntStream;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -42,13 +51,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.OptionalInt;
-import java.util.stream.IntStream;
-
public class NetdEventListenerServiceTest extends TestCase {
// TODO: read from NetdEventListenerService after this constant is read from system property
@@ -68,45 +70,48 @@
}
}
+ private static final String EXAMPLE_IPV4 = "192.0.2.1";
+ private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
+
NetdEventListenerService mNetdEventListenerService;
@Mock ConnectivityManager mCm;
@Mock IpConnectivityLog mLog;
ArgumentCaptor<NetworkCallback> mCallbackCaptor;
- ArgumentCaptor<DnsEvent> mEvCaptor;
+ ArgumentCaptor<DnsEvent> mDnsEvCaptor;
public void setUp() {
MockitoAnnotations.initMocks(this);
mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
- mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
+ mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class);
mNetdEventListenerService = new NetdEventListenerService(mCm, mLog);
verify(mCm, times(1)).registerNetworkCallback(any(), mCallbackCaptor.capture());
}
@SmallTest
- public void testOneBatch() throws Exception {
+ public void testOneDnsBatch() throws Exception {
log(105, LATENCIES);
log(106, Arrays.copyOf(LATENCIES, BATCH_SIZE - 1)); // one lookup short of a batch event
- verifyLoggedEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
+ verifyLoggedDnsEvents(new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
log(106, Arrays.copyOfRange(LATENCIES, BATCH_SIZE - 1, BATCH_SIZE));
- mEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
- verifyLoggedEvents(
+ mDnsEvCaptor = ArgumentCaptor.forClass(DnsEvent.class); // reset argument captor
+ verifyLoggedDnsEvents(
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
@SmallTest
- public void testSeveralBatches() throws Exception {
+ public void testSeveralDmsBatches() throws Exception {
log(105, LATENCIES);
log(106, LATENCIES);
log(105, LATENCIES);
log(107, LATENCIES);
- verifyLoggedEvents(
+ verifyLoggedDnsEvents(
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
@@ -114,7 +119,7 @@
}
@SmallTest
- public void testBatchAndNetworkLost() throws Exception {
+ public void testDnsBatchAndNetworkLost() throws Exception {
byte[] eventTypes = Arrays.copyOf(EVENT_TYPES, 20);
byte[] returnCodes = Arrays.copyOf(RETURN_CODES, 20);
int[] latencies = Arrays.copyOf(LATENCIES, 20);
@@ -124,14 +129,14 @@
mCallbackCaptor.getValue().onLost(new Network(105));
log(105, LATENCIES);
- verifyLoggedEvents(
+ verifyLoggedDnsEvents(
new DnsEvent(105, eventTypes, returnCodes, latencies),
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
@SmallTest
- public void testConcurrentBatchesAndDumps() throws Exception {
+ public void testConcurrentDnsBatchesAndDumps() throws Exception {
final long stop = System.currentTimeMillis() + 100;
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
new Thread() {
@@ -142,27 +147,121 @@
}
}.start();
- logAsync(105, LATENCIES);
- logAsync(106, LATENCIES);
- logAsync(107, LATENCIES);
+ logDnsAsync(105, LATENCIES);
+ logDnsAsync(106, LATENCIES);
+ logDnsAsync(107, LATENCIES);
- verifyLoggedEvents(500,
+ verifyLoggedDnsEvents(500,
new DnsEvent(105, EVENT_TYPES, RETURN_CODES, LATENCIES),
new DnsEvent(106, EVENT_TYPES, RETURN_CODES, LATENCIES),
new DnsEvent(107, EVENT_TYPES, RETURN_CODES, LATENCIES));
}
@SmallTest
- public void testConcurrentBatchesAndNetworkLoss() throws Exception {
- logAsync(105, LATENCIES);
+ public void testConcurrentDnsBatchesAndNetworkLoss() throws Exception {
+ logDnsAsync(105, LATENCIES);
Thread.sleep(10L);
- // call onLost() asynchronously to logAsync's onDnsEvent() calls.
+ // call onLost() asynchronously to logDnsAsync's onDnsEvent() calls.
mCallbackCaptor.getValue().onLost(new Network(105));
// do not verify unpredictable batch
verify(mLog, timeout(500).times(1)).log(any());
}
+ @SmallTest
+ public void testConnectLogging() throws Exception {
+ final int OK = 0;
+ Thread[] logActions = {
+ // ignored
+ connectEventAction(OsConstants.EALREADY, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.EALREADY, 0, EXAMPLE_IPV6),
+ connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
+ connectEventAction(OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
+ // valid latencies
+ connectEventAction(OK, 110, EXAMPLE_IPV4),
+ connectEventAction(OK, 23, EXAMPLE_IPV4),
+ connectEventAction(OK, 45, EXAMPLE_IPV4),
+ connectEventAction(OK, 56, EXAMPLE_IPV4),
+ connectEventAction(OK, 523, EXAMPLE_IPV6),
+ connectEventAction(OK, 214, EXAMPLE_IPV6),
+ connectEventAction(OK, 67, EXAMPLE_IPV6),
+ // errors
+ connectEventAction(OsConstants.EPERM, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.EPERM, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.EAGAIN, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.EACCES, 0, EXAMPLE_IPV6),
+ connectEventAction(OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4),
+ connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
+ connectEventAction(OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
+ connectEventAction(OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4),
+ };
+
+ for (Thread t : logActions) {
+ t.start();
+ }
+ for (Thread t : logActions) {
+ t.join();
+ }
+
+ List<IpConnectivityEvent> events = new ArrayList<>();
+ mNetdEventListenerService.flushStatistics(events);
+
+ IpConnectivityEvent got = events.get(0);
+ String want = joinLines(
+ "connect_statistics <",
+ " connect_count: 12",
+ " errnos_counters <",
+ " key: 1",
+ " value: 2",
+ " >",
+ " errnos_counters <",
+ " key: 11",
+ " value: 1",
+ " >",
+ " errnos_counters <",
+ " key: 13",
+ " value: 3",
+ " >",
+ " errnos_counters <",
+ " key: 98",
+ " value: 1",
+ " >",
+ " errnos_counters <",
+ " key: 110",
+ " value: 3",
+ " >",
+ " errnos_counters <",
+ " key: 111",
+ " value: 1",
+ " >",
+ " ipv6_addr_count: 6",
+ " latencies_ms: 23",
+ " latencies_ms: 45",
+ " latencies_ms: 56",
+ " latencies_ms: 67",
+ " latencies_ms: 110",
+ " latencies_ms: 214",
+ " latencies_ms: 523",
+ ">",
+ "time_ms: 0",
+ "transport: 0");
+ verifyConnectEvent(want, got);
+ }
+
+ Thread connectEventAction(int error, int latencyMs, String ipAddr) {
+ return new Thread(() -> {
+ try {
+ mNetdEventListenerService.onConnectEvent(100, error, latencyMs, ipAddr, 80, 1);
+ } catch (Exception e) {
+ fail(e.toString());
+ }
+ });
+ }
+
void log(int netId, int[] latencies) {
try {
for (int l : latencies) {
@@ -174,7 +273,7 @@
}
}
- void logAsync(int netId, int[] latencies) {
+ void logDnsAsync(int netId, int[] latencies) {
new Thread() {
public void run() {
log(netId, latencies);
@@ -182,15 +281,15 @@
}.start();
}
- void verifyLoggedEvents(DnsEvent... expected) {
- verifyLoggedEvents(0, expected);
+ void verifyLoggedDnsEvents(DnsEvent... expected) {
+ verifyLoggedDnsEvents(0, expected);
}
- void verifyLoggedEvents(int wait, DnsEvent... expectedEvents) {
- verify(mLog, timeout(wait).times(expectedEvents.length)).log(mEvCaptor.capture());
- for (DnsEvent got : mEvCaptor.getAllValues()) {
+ void verifyLoggedDnsEvents(int wait, DnsEvent... expectedEvents) {
+ verify(mLog, timeout(wait).times(expectedEvents.length)).log(mDnsEvCaptor.capture());
+ for (DnsEvent got : mDnsEvCaptor.getAllValues()) {
OptionalInt index = IntStream.range(0, expectedEvents.length)
- .filter(i -> eventsEqual(expectedEvents[i], got))
+ .filter(i -> dnsEventsEqual(expectedEvents[i], got))
.findFirst();
// Don't match same expected event more than once.
index.ifPresent(i -> expectedEvents[i] = null);
@@ -199,11 +298,30 @@
}
/** equality function for DnsEvent to avoid overriding equals() and hashCode(). */
- static boolean eventsEqual(DnsEvent expected, DnsEvent got) {
+ static boolean dnsEventsEqual(DnsEvent expected, DnsEvent got) {
return (expected == got) || ((expected != null) && (got != null)
&& (expected.netId == got.netId)
&& Arrays.equals(expected.eventTypes, got.eventTypes)
&& Arrays.equals(expected.returnCodes, got.returnCodes)
&& Arrays.equals(expected.latenciesMs, got.latenciesMs));
}
+
+ static String joinLines(String ... elems) {
+ StringBuilder b = new StringBuilder();
+ for (String s : elems) {
+ b.append(s).append("\n");
+ }
+ return b.toString();
+ }
+
+ static void verifyConnectEvent(String expected, IpConnectivityEvent got) {
+ try {
+ Arrays.sort(got.connectStatistics.latenciesMs);
+ Arrays.sort(got.connectStatistics.errnosCounters,
+ Comparator.comparingInt((p) -> p.key));
+ assertEquals(expected, got.toString());
+ } catch (Exception e) {
+ fail(e.toString());
+ }
+ }
}