summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/Clock.java6
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java96
-rw-r--r--service/proto/src/metrics.proto17
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java196
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.
*