From 7742c758bcea64b00d0aac2a25140eab9c89d8e5 Mon Sep 17 00:00:00 2001 From: David Su Date: Sun, 21 Apr 2019 13:08:46 -0700 Subject: Link Probing: Experiments to vary trigger criteria Run experiments by varying the delay between probes, the delay after screen on, and the delay after last Tx success. Count the number of probes that *would* be triggered by each experiment, and upload to metrics. Bug: 131091030 Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: Id795b8acb86c4e64672e3ca5a9147647d93a1115 --- .../com/android/server/wifi/ClientModeImpl.java | 4 +- .../com/android/server/wifi/LinkProbeManager.java | 152 ++++++++++++++++++--- .../java/com/android/server/wifi/WifiMetrics.java | 44 ++++-- .../android/server/wifi/ClientModeImplTest.java | 6 +- .../android/server/wifi/LinkProbeManagerTest.java | 22 ++- .../com/android/server/wifi/WifiMetricsTest.java | 29 ++++ .../android/server/wifi/WifiMetricsTestUtil.java | 38 ++++++ 7 files changed, 260 insertions(+), 35 deletions(-) diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java index 2ae6b4ed5..6170ee820 100644 --- a/service/java/com/android/server/wifi/ClientModeImpl.java +++ b/service/java/com/android/server/wifi/ClientModeImpl.java @@ -4896,7 +4896,7 @@ public class ClientModeImpl extends StateMachine { public void enter() { mRssiPollToken++; if (mEnableRssiPolling) { - mLinkProbeManager.reset(); + mLinkProbeManager.resetOnNewConnection(); sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); } if (mNetworkAgent != null) { @@ -5118,7 +5118,7 @@ public class ClientModeImpl extends StateMachine { if (mEnableRssiPolling) { // First poll mLastSignalLevel = -1; - mLinkProbeManager.reset(); + mLinkProbeManager.resetOnScreenTurnedOn(); fetchRssiLinkSpeedAndFrequencyNative(); sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), mPollRssiIntervalMsecs); diff --git a/service/java/com/android/server/wifi/LinkProbeManager.java b/service/java/com/android/server/wifi/LinkProbeManager.java index ff26991f1..b91ba67f4 100644 --- a/service/java/com/android/server/wifi/LinkProbeManager.java +++ b/service/java/com/android/server/wifi/LinkProbeManager.java @@ -30,6 +30,8 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; /** * Tracks state that decides if a link probe should be performed. If so, trigger a link probe to @@ -48,6 +50,10 @@ public class LinkProbeManager { @VisibleForTesting static final long LINK_PROBE_INTERVAL_MS = 15 * 1000; + @VisibleForTesting + static final int[] EXPERIMENT_DELAYS_MS = {3000, 6000, 9000, 12000, 15000}; + private List mExperiments = new ArrayList<>(); + private final Clock mClock; private final WifiNative mWifiNative; private final WifiMetrics mWifiMetrics; @@ -63,7 +69,7 @@ public class LinkProbeManager { /** * Tracks the last timestamp when wifiInfo.txSuccess was increased i.e. the last time a Tx was * successful. Link probing only occurs when at least {@link #LINK_PROBE_INTERVAL_MS} has passed - * since the last Tx succcess. + * since the last Tx success. * This is also reset to the current time when {@link #reset()} is called, so that a link probe * only occurs at least {@link #LINK_PROBE_INTERVAL_MS} after a new connection is made. */ @@ -79,19 +85,22 @@ public class LinkProbeManager { mContext = context; mLinkProbingSupported = mContext.getResources() .getBoolean(R.bool.config_wifi_link_probing_supported); - if (!mLinkProbingSupported) return; - mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor( - Settings.Global.WIFI_LINK_PROBING_ENABLED), false, - new ContentObserver(new Handler(looper)) { - @Override - public void onChange(boolean selfChange) { - updateLinkProbeSetting(); - } - }); - updateLinkProbeSetting(); + if (mLinkProbingSupported) { + mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor( + Settings.Global.WIFI_LINK_PROBING_ENABLED), false, + new ContentObserver(new Handler(looper)) { + @Override + public void onChange(boolean selfChange) { + updateLinkProbeSetting(); + } + }); + updateLinkProbeSetting(); - reset(); + reset(); + } + + initExperiments(); } private void updateLinkProbeSetting() { @@ -117,11 +126,7 @@ public class LinkProbeManager { pw.println("LinkProbeManager - mLastTxSuccessCount: " + mLastTxSuccessCount); } - /** - * When connecting to a different network or when RSSI poll events are stopped and restarted, - * reset internal state. - */ - public void reset() { + private void reset() { if (!mLinkProbingSupported) return; long now = mClock.getElapsedSinceBootMillis(); @@ -130,6 +135,23 @@ public class LinkProbeManager { mLastTxSuccessCount = 0; } + /** + * When connecting to a new network, reset internal state. + */ + public void resetOnNewConnection() { + mExperiments.forEach(Experiment::resetOnNewConnection); + reset(); + } + + /** + * When RSSI poll events are stopped and restarted (usually screen turned off then back on), + * reset internal state. + */ + public void resetOnScreenTurnedOn() { + mExperiments.forEach(Experiment::resetOnScreenTurnedOn); + reset(); + } + /** * Based on network conditions provided by WifiInfo, decides if a link probe should be * performed. If so, trigger a link probe and report the results to WifiMetrics. @@ -138,6 +160,8 @@ public class LinkProbeManager { * @param interfaceName the interface that the link probe should be performed on, if applicable. */ public void updateConnectionStats(WifiInfo wifiInfo, String interfaceName) { + mExperiments.forEach(e -> e.updateConnectionStats(wifiInfo)); + if (!mLinkProbingSupported) return; long now = mClock.getElapsedSinceBootMillis(); @@ -209,4 +233,98 @@ public class LinkProbeManager { mLastLinkProbeTimestampMs = mClock.getElapsedSinceBootMillis(); } + + private void initExperiments() { + for (int screenOnDelayMs : EXPERIMENT_DELAYS_MS) { + for (int noTxDelayMs : EXPERIMENT_DELAYS_MS) { + for (int delayBetweenProbesMs : EXPERIMENT_DELAYS_MS) { + Experiment experiment = new Experiment(mClock, mWifiMetrics, + screenOnDelayMs, noTxDelayMs, delayBetweenProbesMs); + mExperiments.add(experiment); + } + } + } + } + + // TODO(b/131091030): remove once experiment is over + private static class Experiment { + + private final Clock mClock; + private final WifiMetrics mWifiMetrics; + private final int mScreenOnDelayMs; + private final int mNoTxDelayMs; + private final int mDelayBetweenProbesMs; + private final String mExperimentId; + + private long mLastLinkProbeTimestampMs; + private long mLastTxSuccessIncreaseTimestampMs; + private long mLastTxSuccessCount; + + Experiment(Clock clock, WifiMetrics wifiMetrics, + int screenOnDelayMs, int noTxDelayMs, int delayBetweenProbesMs) { + mClock = clock; + mWifiMetrics = wifiMetrics; + mScreenOnDelayMs = screenOnDelayMs; + mNoTxDelayMs = noTxDelayMs; + mDelayBetweenProbesMs = delayBetweenProbesMs; + + mExperimentId = getExperimentId(); + + resetOnNewConnection(); + } + + private String getExperimentId() { + return "[screenOnDelay=" + mScreenOnDelayMs + ',' + + "noTxDelay=" + mNoTxDelayMs + ',' + + "delayBetweenProbes=" + mDelayBetweenProbesMs + ']'; + } + + void resetOnNewConnection() { + long now = mClock.getElapsedSinceBootMillis(); + mLastLinkProbeTimestampMs = now; + mLastTxSuccessIncreaseTimestampMs = now; + mLastTxSuccessCount = 0; + } + + void resetOnScreenTurnedOn() { + long now = mClock.getElapsedSinceBootMillis(); + long firstPossibleLinkProbeAfterScreenOnTimestampMs = now + mScreenOnDelayMs; + mLastLinkProbeTimestampMs = Math.max(mLastLinkProbeTimestampMs, + firstPossibleLinkProbeAfterScreenOnTimestampMs - mDelayBetweenProbesMs); + // don't reset mLastTxSuccessIncreaseTimestampMs and mLastTxSuccessCount since no new + // connection was established + } + + void updateConnectionStats(WifiInfo wifiInfo) { + long now = mClock.getElapsedSinceBootMillis(); + + if (mLastTxSuccessCount < wifiInfo.txSuccess) { + mLastTxSuccessIncreaseTimestampMs = now; + } + mLastTxSuccessCount = wifiInfo.txSuccess; + + long timeSinceLastLinkProbeMs = now - mLastLinkProbeTimestampMs; + if (timeSinceLastLinkProbeMs < mDelayBetweenProbesMs) { + return; + } + + // if tx succeeded at least once in the last LINK_PROBE_INTERVAL_MS, don't need to probe + long timeSinceLastTxSuccessIncreaseMs = now - mLastTxSuccessIncreaseTimestampMs; + if (timeSinceLastTxSuccessIncreaseMs < mNoTxDelayMs) { + return; + } + + // can skip probing if RSSI is valid and high and link speed is fast + int rssi = wifiInfo.getRssi(); + int linkSpeed = wifiInfo.getLinkSpeed(); + if (rssi != WifiInfo.INVALID_RSSI && rssi > LINK_PROBE_RSSI_THRESHOLD + && linkSpeed > LINK_PROBE_LINK_SPEED_THRESHOLD_MBPS) { + return; + } + + mWifiMetrics.incrementLinkProbeExperimentProbeCount(mExperimentId); + + mLastLinkProbeTimestampMs = mClock.getElapsedSinceBootMillis(); + } + } } diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 125cd0987..c1b7fccbb 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -60,6 +60,7 @@ import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificatio import com.android.server.wifi.nano.WifiMetricsProto.DeviceMobilityStatePnoScanStats; import com.android.server.wifi.nano.WifiMetricsProto.ExperimentValues; import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats; +import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.ExperimentProbeCounts; import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount; import com.android.server.wifi.nano.WifiMetricsProto.LinkSpeedCount; import com.android.server.wifi.nano.WifiMetricsProto.NetworkSelectionExperimentDecisions; @@ -85,6 +86,7 @@ import com.android.server.wifi.util.InformationElementUtil; import com.android.server.wifi.util.IntCounter; import com.android.server.wifi.util.IntHistogram; import com.android.server.wifi.util.MetricsUtils; +import com.android.server.wifi.util.ObjectCounter; import com.android.server.wifi.util.ScanResultUtil; import org.json.JSONArray; @@ -319,6 +321,12 @@ public class WifiMetrics { LINK_PROBE_ELAPSED_TIME_MS_HISTOGRAM_BUCKETS); private final IntCounter mLinkProbeFailureReasonCounts = new IntCounter(); + /** + * Maps a String link probe experiment ID to the number of link probes that were sent for this + * experiment. + */ + private final ObjectCounter mLinkProbeExperimentProbeCounts = new ObjectCounter<>(); + private final LinkedList mWifiUsabilityStatsEntriesList = new LinkedList<>(); private final LinkedList mWifiUsabilityStatsListBad = new LinkedList<>(); @@ -2749,6 +2757,7 @@ public class WifiMetrics { pw.println("mLinkProbeSuccessElapsedTimeMsHistogram:" + mLinkProbeSuccessElapsedTimeMsHistogram); pw.println("mLinkProbeFailureReasonCounts:" + mLinkProbeFailureReasonCounts); + pw.println("mLinkProbeExperimentProbeCounts:" + mLinkProbeExperimentProbeCounts); pw.println("mNetworkSelectionExperimentPairNumChoicesCounts:" + mNetworkSelectionExperimentPairNumChoicesCounts); @@ -2774,7 +2783,6 @@ public class WifiMetrics { + mWifiLogProto.numAddOrUpdateNetworkCalls); pw.println("mWifiLogProto.numEnableNetworkCalls=" + mWifiLogProto.numEnableNetworkCalls); - } } } @@ -3268,14 +3276,22 @@ public class WifiMetrics { mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.toProto(); linkProbeStats.successElapsedTimeMsHistogram = mLinkProbeSuccessElapsedTimeMsHistogram.toProto(); - linkProbeStats.failureReasonCounts = - mLinkProbeFailureReasonCounts.toProto(LinkProbeFailureReasonCount.class, - (reason, count) -> { - LinkProbeFailureReasonCount c = new LinkProbeFailureReasonCount(); - c.failureReason = linkProbeFailureReasonToProto(reason); - c.count = count; - return c; - }); + linkProbeStats.failureReasonCounts = mLinkProbeFailureReasonCounts.toProto( + LinkProbeFailureReasonCount.class, + (reason, count) -> { + LinkProbeFailureReasonCount c = new LinkProbeFailureReasonCount(); + c.failureReason = linkProbeFailureReasonToProto(reason); + c.count = count; + return c; + }); + linkProbeStats.experimentProbeCounts = mLinkProbeExperimentProbeCounts.toProto( + ExperimentProbeCounts.class, + (experimentId, probeCount) -> { + ExperimentProbeCounts c = new ExperimentProbeCounts(); + c.experimentId = experimentId; + c.probeCount = probeCount; + return c; + }); mWifiLogProto.linkProbeStats = linkProbeStats; mWifiLogProto.networkSelectionExperimentDecisionsList = @@ -3489,6 +3505,7 @@ public class WifiMetrics { mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.clear(); mLinkProbeSuccessElapsedTimeMsHistogram.clear(); mLinkProbeFailureReasonCounts.clear(); + mLinkProbeExperimentProbeCounts.clear(); mNetworkSelectionExperimentPairNumChoicesCounts.clear(); mWifiNetworkSuggestionApiLog.clear(); mWifiNetworkSuggestionApiLog.clear(); @@ -4722,6 +4739,15 @@ public class WifiMetrics { } } + /** + * Increments the number of probes triggered by the experiment `experimentId`. + */ + public void incrementLinkProbeExperimentProbeCount(String experimentId) { + synchronized (mLock) { + mLinkProbeExperimentProbeCounts.increment(experimentId); + } + } + /** * Update wifi config store read duration. * diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java index 452dfa399..b96fc3a90 100644 --- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java +++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java @@ -3270,7 +3270,8 @@ public class ClientModeImplTest { connect(); // reset() should be called when RSSI polling is enabled and entering L2ConnectedState - verify(mLinkProbeManager).reset(); + verify(mLinkProbeManager).resetOnNewConnection(); // called first time here + verify(mLinkProbeManager, never()).resetOnScreenTurnedOn(); // not called verify(mLinkProbeManager).updateConnectionStats(any(), any()); mCmi.enableRssiPolling(false); @@ -3279,7 +3280,8 @@ public class ClientModeImplTest { // becomes enabled mCmi.enableRssiPolling(true); mLooper.dispatchAll(); - verify(mLinkProbeManager, times(2)).reset(); + verify(mLinkProbeManager, times(1)).resetOnNewConnection(); // verify not called again + verify(mLinkProbeManager).resetOnScreenTurnedOn(); // verify called here } /** diff --git a/tests/wifitests/src/com/android/server/wifi/LinkProbeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/LinkProbeManagerTest.java index 614ec7e57..35f63149c 100644 --- a/tests/wifitests/src/com/android/server/wifi/LinkProbeManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/LinkProbeManagerTest.java @@ -16,9 +16,12 @@ package com.android.server.wifi; +import static junit.framework.Assert.assertEquals; + import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -40,6 +43,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.HashSet; + /** * Unit tests for LinkProbeManager */ @@ -102,7 +107,7 @@ public class LinkProbeManagerTest { */ @Test public void testLinkProbeTriggeredAndAcked() throws Exception { - mLinkProbeManager.reset(); + mLinkProbeManager.resetOnNewConnection(); // initialize tx success counter mWifiInfo.txSuccess = 50; @@ -111,6 +116,7 @@ public class LinkProbeManagerTest { mLinkProbeManager.updateConnectionStats(mWifiInfo, TEST_IFACE_NAME); // should not probe yet verify(mWifiNative, never()).probeLink(any(), any(), any(), anyInt()); + verify(mWifiMetrics, never()).incrementLinkProbeExperimentProbeCount(any()); // tx success counter did not change since last update mWifiInfo.txSuccess = 50; @@ -130,6 +136,12 @@ public class LinkProbeManagerTest { ArgumentCaptor.forClass(WifiNative.SendMgmtFrameCallback.class); verify(mWifiNative).probeLink(eq(TEST_IFACE_NAME), any(), callbackCaptor.capture(), anyInt()); + ArgumentCaptor experimentIdCaptor = ArgumentCaptor.forClass(String.class); + verify(mWifiMetrics, atLeastOnce()).incrementLinkProbeExperimentProbeCount( + experimentIdCaptor.capture()); + int len = LinkProbeManager.EXPERIMENT_DELAYS_MS.length; + int numExperimentIds = len * len * len; + assertEquals(numExperimentIds, new HashSet<>(experimentIdCaptor.getAllValues()).size()); callbackCaptor.getValue().onAck(TEST_ELAPSED_TIME_MS); verify(mWifiMetrics).logLinkProbeSuccess(TEST_TIMESTAMP_MS, timeDelta, rssi, linkSpeed, @@ -142,7 +154,7 @@ public class LinkProbeManagerTest { */ @Test public void testLinkProbeTriggeredAndFailed() throws Exception { - mLinkProbeManager.reset(); + mLinkProbeManager.resetOnNewConnection(); // initialize tx success counter mWifiInfo.txSuccess = 50; @@ -203,7 +215,7 @@ public class LinkProbeManagerTest { */ @Test public void testLinkProbeNotTriggeredWhenTxSucceeded() throws Exception { - mLinkProbeManager.reset(); + mLinkProbeManager.resetOnNewConnection(); // initialize tx success counter mWifiInfo.txSuccess = 50; @@ -243,7 +255,7 @@ public class LinkProbeManagerTest { eq(Settings.Global.WIFI_LINK_PROBING_ENABLED), anyInt())).thenReturn(0); mContentObserver.onChange(false); - mLinkProbeManager.reset(); + mLinkProbeManager.resetOnNewConnection(); // initialize tx success counter mWifiInfo.txSuccess = 50; @@ -278,7 +290,7 @@ public class LinkProbeManagerTest { mResources.setBoolean(R.bool.config_wifi_link_probing_supported, false); initLinkProbeManager(); - mLinkProbeManager.reset(); + mLinkProbeManager.resetOnNewConnection(); // initialize tx success counter mWifiInfo.txSuccess = 50; diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java index 9b9f032ce..a55f1d29c 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java @@ -21,11 +21,13 @@ import static android.net.wifi.WifiManager.DEVICE_MOBILITY_STATE_STATIONARY; import static android.net.wifi.WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN; import static com.android.server.wifi.WifiMetricsTestUtil.assertDeviceMobilityStatePnoScanStatsEqual; +import static com.android.server.wifi.WifiMetricsTestUtil.assertExperimentProbeCountsEqual; import static com.android.server.wifi.WifiMetricsTestUtil.assertHistogramBucketsEqual; import static com.android.server.wifi.WifiMetricsTestUtil.assertKeyCountsEqual; import static com.android.server.wifi.WifiMetricsTestUtil.assertLinkProbeFailureReasonCountsEqual; import static com.android.server.wifi.WifiMetricsTestUtil.assertLinkProbeStaEventsEqual; import static com.android.server.wifi.WifiMetricsTestUtil.buildDeviceMobilityStatePnoScanStats; +import static com.android.server.wifi.WifiMetricsTestUtil.buildExperimentProbeCounts; import static com.android.server.wifi.WifiMetricsTestUtil.buildHistogramBucketInt32; import static com.android.server.wifi.WifiMetricsTestUtil.buildInt32Count; import static com.android.server.wifi.WifiMetricsTestUtil.buildLinkProbeFailureReasonCount; @@ -85,6 +87,7 @@ import com.android.server.wifi.nano.WifiMetricsProto.DeviceMobilityStatePnoScanS import com.android.server.wifi.nano.WifiMetricsProto.HistogramBucketInt32; import com.android.server.wifi.nano.WifiMetricsProto.Int32Count; import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats; +import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.ExperimentProbeCounts; import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount; import com.android.server.wifi.nano.WifiMetricsProto.NetworkSelectionExperimentDecisions; import com.android.server.wifi.nano.WifiMetricsProto.PasspointProfileTypeCount; @@ -3466,6 +3469,32 @@ public class WifiMetricsTest { linkProbeStats.failureReasonCounts); } + /** + * Tests counting the number of link probes triggered per day for each experiment. + */ + @Test + public void testIncrementLinkProbeExperimentProbeCount() throws Exception { + String experimentId1 = "screenOnDelay=6000,noTxDelay=3000,delayBetweenProbes=9000," + + "rssiThreshold=-70,linkSpeedThreshold=15,"; + mWifiMetrics.incrementLinkProbeExperimentProbeCount(experimentId1); + + String experimentId2 = "screenOnDelay=9000,noTxDelay=12000,delayBetweenProbes=15000," + + "rssiThreshold=-72,linkSpeedThreshold=20,"; + mWifiMetrics.incrementLinkProbeExperimentProbeCount(experimentId2); + mWifiMetrics.incrementLinkProbeExperimentProbeCount(experimentId2); + + dumpProtoAndDeserialize(); + + ExperimentProbeCounts[] actual = mDecodedProto.linkProbeStats.experimentProbeCounts; + + ExperimentProbeCounts[] expected = { + buildExperimentProbeCounts(experimentId1, 1), + buildExperimentProbeCounts(experimentId2, 2) + }; + + assertExperimentProbeCountsEqual(expected, actual); + } + /** * Tests logNetworkSelectionDecision() */ diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTestUtil.java index 407d20932..0e9f661ca 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTestUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTestUtil.java @@ -23,6 +23,7 @@ import android.net.wifi.WifiManager; import com.android.server.wifi.nano.WifiMetricsProto.DeviceMobilityStatePnoScanStats; import com.android.server.wifi.nano.WifiMetricsProto.HistogramBucketInt32; import com.android.server.wifi.nano.WifiMetricsProto.Int32Count; +import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.ExperimentProbeCounts; import com.android.server.wifi.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount; import com.android.server.wifi.nano.WifiMetricsProto.StaEvent; @@ -227,4 +228,41 @@ public class WifiMetricsTestUtil { } } } + + /** + * The constructor we wish ExperimentProbeCounts had. + */ + public static ExperimentProbeCounts buildExperimentProbeCounts( + String experimentId, int probeCount) { + ExperimentProbeCounts counts = new ExperimentProbeCounts(); + counts.experimentId = experimentId; + counts.probeCount = probeCount; + return counts; + } + + /** + * Asserts that the two arrays are equal (ignoring order), + * reporting any difference between them. + */ + public static void assertExperimentProbeCountsEqual( + ExperimentProbeCounts[] expected, ExperimentProbeCounts[] actual) { + + assertEquals("Number of ExperimentProbeCounts do not match!", + expected.length, actual.length); + + Arrays.sort(expected, Comparator.comparing(x -> x.experimentId)); + Arrays.sort(actual, Comparator.comparing(x -> x.experimentId)); + + for (int i = 0; i < expected.length; i++) { + ExperimentProbeCounts expectedCounts = expected[i]; + ExperimentProbeCounts actualCounts = actual[i]; + + assertEquals(String.format( + "ExperimentProbeCounts[%d].experimentId does not match!", i), + expectedCounts.experimentId, actualCounts.experimentId); + assertEquals(String.format( + "ExperimentProbeCounts[%d].probeCount does not match!", i), + expectedCounts.probeCount, actualCounts.probeCount); + } + } } -- cgit v1.2.3