diff options
-rw-r--r-- | service/java/com/android/server/wifi/Clock.java | 6 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiMetrics.java | 96 | ||||
-rw-r--r-- | service/proto/src/metrics.proto | 17 | ||||
-rw-r--r-- | service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java | 196 |
4 files changed, 308 insertions, 7 deletions
diff --git a/service/java/com/android/server/wifi/Clock.java b/service/java/com/android/server/wifi/Clock.java index 63e958b3ca..1a235287cb 100644 --- a/service/java/com/android/server/wifi/Clock.java +++ b/service/java/com/android/server/wifi/Clock.java @@ -18,6 +18,8 @@ package com.android.server.wifi; import android.os.SystemClock; +import java.time.Instant; + import javax.annotation.concurrent.ThreadSafe; /** @@ -68,4 +70,8 @@ public class Clock { public void sleep(long ms) { SystemClock.sleep(ms); } + + public Instant getCurrentInstant() { + return Instant.now(); + } } diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java index 1f9d54a927..8be74e57de 100644 --- a/service/java/com/android/server/wifi/WifiMetrics.java +++ b/service/java/com/android/server/wifi/WifiMetrics.java @@ -144,6 +144,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.SoftApConnectedClient import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent.ConfigInfo; import com.android.server.wifi.proto.nano.WifiMetricsProto.TargetNetworkInfo; +import com.android.server.wifi.proto.nano.WifiMetricsProto.TrainingData; import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.UserReactionToApprovalUiEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.UserReactionToApprovalUiEvent.UserReaction; @@ -158,6 +159,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToWifiSwitchStats import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToggleStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats; // This contains a time series of WifiUsabilityStatsEntry along with some metadata, such as the label of the time series or trigger type. import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsEntry; // This contains all the stats for a single point in time. +import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsTraining; import com.android.server.wifi.rtt.RttMetrics; import com.android.server.wifi.scanner.KnownBandsChannelHelper; import com.android.server.wifi.util.InformationElementUtil; @@ -178,6 +180,8 @@ import org.json.JSONObject; import java.io.FileDescriptor; import java.io.PrintWriter; import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; @@ -244,6 +248,7 @@ public class WifiMetrics { public static final int MIN_DATA_STALL_WAIT_MS = 120 * 1000; // 2 minutes // Max number of WifiUsabilityStatsEntry elements to store in the ringbuffer. public static final int MAX_WIFI_USABILITY_STATS_ENTRIES_RING_BUFFER_SIZE = 80; + public static final int MAX_WIFI_USABILITY_STATS_TRAINING_SIZE = 10; // Max number of WifiUsabilityStats records to store for each type. public static final int MAX_WIFI_USABILITY_STATS_RECORDS_PER_TYPE = 10; // Max number of WifiUsabilityStats per labeled type to upload to server @@ -280,6 +285,8 @@ public class WifiMetrics { public static final int MIN_DOWNSTREAM_BANDWIDTH_KBPS = 1000; public static final int MIN_UPSTREAM_BANDWIDTH_KBPS = 1000; public static final int INVALID_SPEED = -1; + public static final long MILLIS_IN_A_SECOND = 1000; + public static final long MILLIS_IN_AN_HOUR = 3600 * 1000; private Clock mClock; private boolean mScreenOn; @@ -500,6 +507,12 @@ public class WifiMetrics { @VisibleForTesting public final LinkedList<WifiUsabilityStatsEntry> mWifiUsabilityStatsEntriesRingBuffer = new LinkedList<>(); + // Each WifiUsabilityStatsTraining instance contains a list of WifiUsabilityStatsEntry objects, + // representing a time series of WiFi usability statistics recorded within a specific data + // capture period. It also includes information about the type of data capture and the duration + // of the capture period. + public final List<WifiUsabilityStatsTraining> mWifiUsabilityStatsTrainingExamples = + new ArrayList<>(); // One WifiUsabilityStats contains a single time series of WifiUsabilityStatsEntry along with // some metadata. These LinkedList's below contain sets of time series that are labeled as // either 'good' or 'bad'. @@ -5001,6 +5014,17 @@ public class WifiMetrics { printWifiUsabilityStatsEntry(pw, stats); } + pw.println("mWifiUsabilityStatsTrainingExamples:"); + for (WifiUsabilityStatsTraining statsTraining + : mWifiUsabilityStatsTrainingExamples) { + pw.println("\ndata_capture_type=" + statsTraining.dataCaptureType); + pw.println("\ncapture_start_timestamp_secs=" + + statsTraining.captureStartTimestampSecs); + for (WifiUsabilityStatsEntry stats : statsTraining.trainingData.stats) { + printWifiUsabilityStatsEntry(pw, stats); + } + } + pw.println("mMobilityStatePnoStatsMap:"); for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) { printDeviceMobilityStatePnoScanStats(pw, mMobilityStatePnoStatsMap.valueAt(i)); @@ -5768,6 +5792,12 @@ public class WifiMetrics { } mWifiLogProto.hardwareRevision = SystemProperties.get("ro.boot.revision", ""); + mWifiLogProto.wifiUsabilityStatsTraining = + new WifiUsabilityStatsTraining[mWifiUsabilityStatsTrainingExamples.size()]; + for (int i = 0; i < mWifiUsabilityStatsTrainingExamples.size(); i++) { + mWifiLogProto.wifiUsabilityStatsTraining[i] = + mWifiUsabilityStatsTrainingExamples.remove(0); + } mWifiLogProto.mobilityStatePnoStatsList = new DeviceMobilityStatePnoScanStats[mMobilityStatePnoStatsMap.size()]; for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) { @@ -7163,10 +7193,62 @@ public class WifiMetrics { */ public int storeCapturedData(int triggerType, boolean isFullCapture, long triggerStartTimeMillis, long triggerStopTimeMillis) { - // TODO: Implement how to extract WifiUsabilityStatsEntries from ring buffer whose - // timestamps are within [triggerStartTimeMillis, triggerStopTimeMillis] Log.d(TAG, "storeCapturedData: triggerType=" + triggerType + ", isFullCapture=" + isFullCapture); + + // Validate triggerStartTimeMillis and triggerStopTimeMillis in non full-capture case + if (!isFullCapture && ((triggerStartTimeMillis < 0 || triggerStopTimeMillis < 0 + || triggerStopTimeMillis <= triggerStartTimeMillis))) { + return 1; + } + + Instant now = mClock.getCurrentInstant(); + Duration durationSinceBoot = Duration.ofMillis(mClock.getElapsedSinceBootMillis()); + + WifiUsabilityStatsTraining wifiUsabilityStatsTraining = new WifiUsabilityStatsTraining(); + while (mWifiUsabilityStatsTrainingExamples.size() + >= MAX_WIFI_USABILITY_STATS_TRAINING_SIZE) { + mWifiUsabilityStatsTrainingExamples.remove(0); + } + wifiUsabilityStatsTraining.dataCaptureType = triggerType; + + long capturePeriodStartTime = triggerStartTimeMillis; + long capturePeriodStopTime = triggerStopTimeMillis; + + if (isFullCapture) { + capturePeriodStartTime = mWifiUsabilityStatsEntriesRingBuffer.size() > 0 + ? mWifiUsabilityStatsEntriesRingBuffer.get(0).timeStampMs : + 0; + capturePeriodStopTime = mWifiUsabilityStatsEntriesRingBuffer.size() > 0 + ? mWifiUsabilityStatsEntriesRingBuffer.get( + mWifiUsabilityStatsEntriesRingBuffer.size() - 1).timeStampMs : + durationSinceBoot.toMillis(); + } + + wifiUsabilityStatsTraining.captureStartTimestampSecs = + now.minus(durationSinceBoot) + .plus(Duration.ofMillis(capturePeriodStartTime)) + .truncatedTo(ChronoUnit.HOURS) + .getEpochSecond(); + wifiUsabilityStatsTraining.storeTimeOffsetMs = + durationSinceBoot.toMillis() - capturePeriodStopTime; + + // If isFullCapture is true, store everything in ring buffer + // If isFullCapture is false, Store WifiUsabilityStatsEntries within capture period + TrainingData trainingData = new TrainingData(); + List<WifiUsabilityStatsEntry> trainingDataList = new ArrayList<>(); + for (WifiUsabilityStatsEntry currStats : mWifiUsabilityStatsEntriesRingBuffer) { + if (isFullCapture || (currStats.timeStampMs >= triggerStartTimeMillis + && currStats.timeStampMs < triggerStopTimeMillis)) { + WifiUsabilityStatsEntry trainingStats = + createNewWifiUsabilityStatsEntry(currStats, capturePeriodStartTime); + trainingDataList.add(trainingStats); + } + } + trainingData.stats = trainingDataList.toArray(new WifiUsabilityStatsEntry[0]); + wifiUsabilityStatsTraining.trainingData = trainingData; + + mWifiUsabilityStatsTrainingExamples.add(wifiUsabilityStatsTraining); return 0; } @@ -8112,9 +8194,11 @@ public class WifiMetrics { } } - private WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntry(WifiUsabilityStatsEntry s) { + private WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntry(WifiUsabilityStatsEntry s, + long referenceTimestampMs) { WifiUsabilityStatsEntry out = new WifiUsabilityStatsEntry(); - out.timeStampMs = s.timeStampMs; + // Privacy review suggests not to upload real timestamp + out.timeStampMs = 0; out.totalTxSuccess = s.totalTxSuccess; out.totalTxRetries = s.totalTxRetries; out.totalTxBad = s.totalTxBad; @@ -8173,6 +8257,7 @@ public class WifiMetrics { out.voipMode = s.voipMode; out.threadDeviceRole = s.threadDeviceRole; out.statusDataStall = s.statusDataStall; + out.timestampOffsetMs = s.timeStampMs - referenceTimestampMs; return out; } @@ -8213,7 +8298,8 @@ public class WifiMetrics { new WifiUsabilityStatsEntry[mWifiUsabilityStatsEntriesRingBuffer.size()]; for (int i = 0; i < mWifiUsabilityStatsEntriesRingBuffer.size(); i++) { wifiUsabilityStats.stats[i] = - createNewWifiUsabilityStatsEntry(mWifiUsabilityStatsEntriesRingBuffer.get(i)); + createNewWifiUsabilityStatsEntry(mWifiUsabilityStatsEntriesRingBuffer.get(i), + 0); } return wifiUsabilityStats; } diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto index 4a53854d81..979f85c981 100644 --- a/service/proto/src/metrics.proto +++ b/service/proto/src/metrics.proto @@ -2535,6 +2535,8 @@ message WifiLinkLayerUsageStats { repeated RadioStats radio_stats = 11; } +// WifiUsabilityStatsEntry will only be uploaded when its timestamp is within the data capture +// period message WifiUsabilityStatsEntry { // Status codes for link probe status enum LinkProbeStatus { @@ -2815,6 +2817,14 @@ message WifiUsabilityStatsEntry { optional int32 capture_event_type_subcode = 64; optional int32 status_data_stall = 65; + + // If the full data capture is being stored (field isFullCapture is true in the function call + // WifiManager.storeCapturedData), this field will represent the time offset between this sample + // and the first sample in the capture buffer. i.e. this field will have the value 0 for the + // first sample in the capture buffer. + // If isFullCapture is false, then this field will be the time offset between the capture start + // time and the timestamp of this sample. + optional int64 timestamp_offset_ms = 66; } message ContentionTimeStats { @@ -3169,6 +3179,13 @@ message WifiUsabilityStatsTraining { optional int64 capture_start_timestamp_secs = 2; optional TrainingData training_data = 3; + + // If isFullCapture is true in the WifiManager.storeCaptureData call, this represents the time + // offset between the last sample in the capture buffer and the time the capture buffer was + // stored. If ring buffer is empty (no last sample), we set store_time_offset_ms to 0. + // If isFullCapture is false, this represents the time between 'capture period stop time' and the + // time the capture buffer was stored. + optional int64 store_time_offset_ms = 4; } message DeviceMobilityStatePnoScanStats { diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java index e317d31dbe..08abfbc4e5 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java @@ -166,6 +166,7 @@ import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiRadioUsage; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats; import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsEntry; +import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsTraining; import com.android.server.wifi.rtt.RttMetrics; import com.android.server.wifi.util.InformationElementUtil; import com.android.wifi.flags.Flags; @@ -186,6 +187,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.StringWriter; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; @@ -219,7 +221,6 @@ public class WifiMetricsTest extends WifiBaseTest { private static final int TEST_CHANNEL = 36; private static final int POLLING_INTERVAL_DEFAULT = 3000; private static final int POLLING_INTERVAL_NOT_DEFAULT = 6000; - private MockitoSession mSession; @Mock Context mContext; MockResources mResources; @@ -329,7 +330,6 @@ public class WifiMetricsTest extends WifiBaseTest { when(mWifiInfo.getFrequency()).thenReturn(5850); when(mWifiInfo.getBSSID()).thenReturn("5G_WiFi"); when(mWifiInfo.getRssi()).thenReturn(-55); - } @After @@ -4355,6 +4355,198 @@ public class WifiMetricsTest extends WifiBaseTest { } /** + * When ring buffer is empty, verify that full-capture will capture empty results + */ + @Test + public void testStoreCapturedDataEmptyRingbufferFullCapture() throws Exception { + Instant testCurrentInstant = + Instant.parse("2024-01-01T00:00:00Z").plus(Duration.ofSeconds(258)); + when(mClock.getCurrentInstant()).thenReturn(testCurrentInstant); + when(mClock.getElapsedSinceBootMillis()).thenReturn((long) 10 + * mWifiMetrics.MILLIS_IN_A_SECOND); + assertEquals(0, mWifiMetrics.mWifiUsabilityStatsEntriesRingBuffer.size()); + mWifiMetrics.storeCapturedData(123, true, 2 * mWifiMetrics.MILLIS_IN_A_SECOND, + 8 * mWifiMetrics.MILLIS_IN_A_SECOND); + dumpProtoAndDeserialize(); + assertEquals(1, mDecodedProto.wifiUsabilityStatsTraining.length); + assertEquals(123, mDecodedProto.wifiUsabilityStatsTraining[0].dataCaptureType); + assertEquals(1704067200, + mDecodedProto.wifiUsabilityStatsTraining[0].captureStartTimestampSecs); + assertEquals(0, mDecodedProto.wifiUsabilityStatsTraining[0].trainingData.stats.length); + assertEquals(0, mDecodedProto.wifiUsabilityStatsTraining[0].storeTimeOffsetMs); + } + + /** + * When ring buffer is empty, verify that non full-capture will capture empty results + */ + @Test + public void testStoreCapturedDataEmptyRingbufferNonFullCapture() throws Exception { + Instant testCurrentInstant = + Instant.parse("2024-01-01T00:00:00Z").plus(Duration.ofSeconds(258)); + when(mClock.getCurrentInstant()).thenReturn(testCurrentInstant); + when(mClock.getElapsedSinceBootMillis()).thenReturn((long) 258 + * mWifiMetrics.MILLIS_IN_A_SECOND); + assertEquals(0, mWifiMetrics.mWifiUsabilityStatsEntriesRingBuffer.size()); + mWifiMetrics.storeCapturedData(123, false, 2 * mWifiMetrics.MILLIS_IN_A_SECOND, + 8 * mWifiMetrics.MILLIS_IN_A_SECOND); + dumpProtoAndDeserialize(); + assertEquals(1, mDecodedProto.wifiUsabilityStatsTraining.length); + assertEquals(123, mDecodedProto.wifiUsabilityStatsTraining[0].dataCaptureType); + assertEquals(1704067200, + mDecodedProto.wifiUsabilityStatsTraining[0].captureStartTimestampSecs); + assertEquals(0, mDecodedProto.wifiUsabilityStatsTraining[0].trainingData.stats.length); + // 258 (current time) - 8 (triggerStopTimeMillis) = 250 + assertEquals(250 * mWifiMetrics.MILLIS_IN_A_SECOND, + mDecodedProto.wifiUsabilityStatsTraining[0].storeTimeOffsetMs); + } + + private void ringBufferSetupForTestStoreCapturedData() { + // Starting from 20s, add a WifiUsabilityStatsEntry into ring buffer every 3s, + // the last timestamp is 20 + 3 * (80-1) = 257s + for (int i = 0; i < mWifiMetrics.MAX_WIFI_USABILITY_STATS_ENTRIES_RING_BUFFER_SIZE; ++i) { + WifiUsabilityStatsEntry entry = new WifiUsabilityStatsEntry(); + entry.timeStampMs = (20 + i * 3) * mWifiMetrics.MILLIS_IN_A_SECOND; + mWifiMetrics.mWifiUsabilityStatsEntriesRingBuffer.add(entry); + } + assertEquals(80, mWifiMetrics.mWifiUsabilityStatsEntriesRingBuffer.size()); + assertEquals(0, mWifiMetrics.mWifiUsabilityStatsTrainingExamples.size()); + // Set current time since boot to 258s + when(mClock.getElapsedSinceBootMillis()).thenReturn((long) 258 + * mWifiMetrics.MILLIS_IN_A_SECOND); + // Assume device boot up time is 2024-01-01, 00:00:00 UTC, unix timestamp in seconds + // is 1704067200 + Instant testCurrentInstant = + Instant.parse("2024-01-01T00:00:00Z").plus(Duration.ofSeconds(258)); + when(mClock.getCurrentInstant()).thenReturn(testCurrentInstant); + } + + /** + * In non full-capture, verify: + * triggerStartTimeMillis has to be positive + */ + @Test + public void testStoreCapturedDataNonFullCaptureStartTimePositive() throws Exception { + ringBufferSetupForTestStoreCapturedData(); + mWifiMetrics.storeCapturedData(1, false, -1 * mWifiMetrics.MILLIS_IN_A_SECOND, + 20 * mWifiMetrics.MILLIS_IN_A_SECOND); + dumpProtoAndDeserialize(); + assertEquals(0, mDecodedProto.wifiUsabilityStatsTraining.length); + } + + /** + * In non full-capture, verify: + * triggerStopTimeMillis has to be positive + */ + @Test + public void testStoreCapturedDataNonFullCaptureStopTimePositive() throws Exception { + ringBufferSetupForTestStoreCapturedData(); + mWifiMetrics.storeCapturedData(1, false, 30 * mWifiMetrics.MILLIS_IN_A_SECOND, + -1 * mWifiMetrics.MILLIS_IN_A_SECOND); + dumpProtoAndDeserialize(); + assertEquals(0, mDecodedProto.wifiUsabilityStatsTraining.length); + } + + /** + * In non full-capture, verify: + * triggerStartTimeMillis must be smaller than triggerStopTimeMillis + */ + @Test + public void testStoreCapturedDataNonFullCaptureStartTimeEalierThanStopTime() throws Exception { + ringBufferSetupForTestStoreCapturedData(); + mWifiMetrics.storeCapturedData(1, false, 30 * mWifiMetrics.MILLIS_IN_A_SECOND, + 20 * mWifiMetrics.MILLIS_IN_A_SECOND); + dumpProtoAndDeserialize(); + assertEquals(0, mDecodedProto.wifiUsabilityStatsTraining.length); + } + + /** + * In non full-capture, verify results + */ + @Test + public void testStoreCapturedDataNonFullCapture() throws Exception { + ringBufferSetupForTestStoreCapturedData(); + // Do a successful capture in [30s, 150s], and verify each field + mWifiMetrics.storeCapturedData(1, false, 30 * mWifiMetrics.MILLIS_IN_A_SECOND, + 150 * mWifiMetrics.MILLIS_IN_A_SECOND); + dumpProtoAndDeserialize(); + assertEquals(1, mDecodedProto.wifiUsabilityStatsTraining.length); + WifiUsabilityStatsTraining result = mDecodedProto.wifiUsabilityStatsTraining[0]; + assertEquals(1, result.dataCaptureType); + assertEquals(1704067200, result.captureStartTimestampSecs); + // 258 (current time) - 150 (triggerStopTimeMillis) = 108 + assertEquals(108 * mWifiMetrics.MILLIS_IN_A_SECOND, result.storeTimeOffsetMs); + // Capture period is 150 - 30 = 120s, 120 / 3 = 40 WifiUsabilityStatsEntries + assertEquals(40, result.trainingData.stats.length); + for (int i = 0; i < 40; ++i) { + WifiUsabilityStatsEntry resultEntry = result.trainingData.stats[i]; + assertEquals(0, resultEntry.timeStampMs); + // The timestamp of WifiUsabilityStatsEntries who are in captured result are: + // 32, 35, ... 149 + assertEquals((2 + 3 * i) * mWifiMetrics.MILLIS_IN_A_SECOND, + resultEntry.timestampOffsetMs); + } + } + + /** + * In full-capture, verify results + */ + @Test + public void testStoreCapturedDataFullCapture() throws Exception { + ringBufferSetupForTestStoreCapturedData(); + // Do a successful full-capture, and verify each field + mWifiMetrics.storeCapturedData(2, true, 30 * mWifiMetrics.MILLIS_IN_A_SECOND, + 150 * mWifiMetrics.MILLIS_IN_A_SECOND); + dumpProtoAndDeserialize(); + assertEquals(1, mDecodedProto.wifiUsabilityStatsTraining.length); + WifiUsabilityStatsTraining result = mDecodedProto.wifiUsabilityStatsTraining[0]; + assertEquals(2, result.dataCaptureType); + assertEquals(1704067200, result.captureStartTimestampSecs); + // 258 (current time) - 257 (triggerStopTimeMillis) = 1 + assertEquals(1 * mWifiMetrics.MILLIS_IN_A_SECOND, result.storeTimeOffsetMs); + // Capture period is 257 - 20 = 237s, (237 / 3) + 1 = 80 WifiUsabilityStatsEntries + assertEquals(mWifiMetrics.MAX_WIFI_USABILITY_STATS_ENTRIES_RING_BUFFER_SIZE, + result.trainingData.stats.length); + for (int i = 0; i < mWifiMetrics.MAX_WIFI_USABILITY_STATS_ENTRIES_RING_BUFFER_SIZE; ++i) { + WifiUsabilityStatsEntry resultEntry = result.trainingData.stats[i]; + assertEquals(0, resultEntry.timeStampMs); + // The timestamps of WifiUsabilityStatsEntries who are in captured result are: + // 20, 23, ... 257, offsets are 0, 3, ... 237 + assertEquals((3 * i) * mWifiMetrics.MILLIS_IN_A_SECOND, + resultEntry.timestampOffsetMs); + } + } + + /** + * Verify wifiUsabilityStatsTraining size limit + */ + @Test + public void testwifiUsabilityStatsTrainingSize() { + ringBufferSetupForTestStoreCapturedData(); + // Do MAX_WIFI_USABILITY_STATS_TRAINING_SIZE times successful data capture + for (int i = 0; i < WifiMetrics.MAX_WIFI_USABILITY_STATS_TRAINING_SIZE; ++i) { + mWifiMetrics.storeCapturedData(2, false, (30 + i * 3) * mWifiMetrics.MILLIS_IN_A_SECOND, + (150 + i * 3) * mWifiMetrics.MILLIS_IN_A_SECOND); + } + assertEquals(WifiMetrics.MAX_WIFI_USABILITY_STATS_TRAINING_SIZE, + mWifiMetrics.mWifiUsabilityStatsTrainingExamples.size()); + // 1st capture period is [30s, 150s), current time is 258s, storeTimeOffsetMs is 108s + assertEquals(108 * mWifiMetrics.MILLIS_IN_A_SECOND, + mWifiMetrics.mWifiUsabilityStatsTrainingExamples.get(0).storeTimeOffsetMs); + + // Do another successful data capture, the size should not grow + mWifiMetrics.storeCapturedData(2, false, + (30 + WifiMetrics.MAX_WIFI_USABILITY_STATS_TRAINING_SIZE) + * mWifiMetrics.MILLIS_IN_A_SECOND, + (150 + WifiMetrics.MAX_WIFI_USABILITY_STATS_TRAINING_SIZE) + * mWifiMetrics.MILLIS_IN_A_SECOND); + assertEquals(WifiMetrics.MAX_WIFI_USABILITY_STATS_TRAINING_SIZE, + mWifiMetrics.mWifiUsabilityStatsTrainingExamples.size()); + // 1st capture period is [33s, 153s), current time is 258s, storeTimeOffsetMs is 105s + assertEquals(105 * mWifiMetrics.MILLIS_IN_A_SECOND, + mWifiMetrics.mWifiUsabilityStatsTrainingExamples.get(0).storeTimeOffsetMs); + } + + /** * Verify that updateWifiUsabilityStatsEntries correctly converts the inputs into * a WifiUsabilityStatsEntry Object and then stores it. * |