1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi.rtt;
18 
19 import static org.hamcrest.core.IsEqual.equalTo;
20 import static org.mockito.Mockito.when;
21 
22 import android.net.MacAddress;
23 import android.net.wifi.rtt.RangingRequest;
24 import android.net.wifi.rtt.RangingResult;
25 import android.net.wifi.rtt.ResponderConfig;
26 import android.os.WorkSource;
27 import android.util.Log;
28 
29 import androidx.test.filters.SmallTest;
30 
31 import com.android.server.wifi.Clock;
32 import com.android.server.wifi.WifiBaseTest;
33 import com.android.server.wifi.proto.nano.WifiMetricsProto;
34 
35 import org.junit.Before;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.rules.ErrorCollector;
39 import org.mockito.Mock;
40 import org.mockito.MockitoAnnotations;
41 
42 import java.io.PrintWriter;
43 import java.io.StringWriter;
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 /**
48  * Unit test harness for RttMetrics
49  */
50 @SmallTest
51 public class RttMetricsTest extends WifiBaseTest {
52     private RttMetrics mDut;
53 
54     @Mock
55     Clock mClock;
56 
57     @Rule
58     public ErrorCollector collector = new ErrorCollector();
59 
60     /**
61      * Pre-test configuration. Initialize and install mocks.
62      */
63     @Before
setUp()64     public void setUp() throws Exception {
65         MockitoAnnotations.initMocks(this);
66 
67         setTime(1);
68         mDut = new RttMetrics(mClock);
69     }
70 
71     /**
72      * Verify that recordRequest() records valid metrics.
73      */
74     @Test
testRecordRequest()75     public void testRecordRequest() {
76         WifiMetricsProto.WifiRttLog log;
77 
78         // no requests
79         log = mDut.consolidateProto();
80         checkMainStats("No requests", log, 0, 0, 0, 0);
81         checkPeerStats("No requests: AP", log.rttToAp, 0, 0, 0, 0, 0, 0, 0, 0);
82         checkPeerStats("No requests: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
83 
84         // multiple AP requests from multiple sources
85         WorkSource ws1 = new WorkSource(10);
86         WorkSource ws2 = new WorkSource(20);
87         ws2.add(10);
88 
89         RangingRequest requestAp1 = getDummyRangingRequest(1, 0);
90         RangingRequest requestAp2 = getDummyRangingRequest(2, 0);
91         RangingRequest requestAp5 = getDummyRangingRequest(5, 0);
92         RangingRequest requestAp6 = getDummyRangingRequest(6, 0);
93 
94         mDut.clear();
95         mDut.recordRequest(ws1, requestAp1);
96         setTime(10); // delta = 9
97         mDut.recordRequest(ws1, requestAp2);
98         setTime(20); // delta = 10
99         mDut.recordRequest(ws1, requestAp5);
100         setTime(21); // delta = 1
101         mDut.recordRequest(ws1, requestAp6);
102         setTime(1000); // delta = 979
103         mDut.recordRequest(ws1, requestAp5);
104         setTime(5000); // delta = 4,000
105         mDut.recordRequest(ws1, requestAp5);
106         setTime(1000000); // delta = 995,000
107         mDut.recordRequest(ws1, requestAp2);
108         mDut.recordRequest(ws2, requestAp5);
109         mDut.recordRequest(ws2, requestAp5);
110         mDut.recordRequest(ws2, requestAp5);
111 
112         log = mDut.consolidateProto();
113         checkMainStats("Sequence AP-only", log, 10, 0, 0, 0);
114 
115         checkPeerStats("Sequence AP-only: AP", log.rttToAp, 10, 41, 2, 2, 4, 0, 0, 5);
116 
117         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumRequestsPerApp[0]",
118                 log.rttToAp.histogramNumRequestsPerApp[0], 1, 10, 1);
119         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumRequestsPerApp[1]",
120                 log.rttToAp.histogramNumRequestsPerApp[1], 10, 100, 1);
121 
122         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[0]",
123                 log.rttToAp.histogramNumPeersPerRequest[0], 1, 1, 1);
124         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[1]",
125                 log.rttToAp.histogramNumPeersPerRequest[1], 2, 2, 2);
126         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[2]",
127                 log.rttToAp.histogramNumPeersPerRequest[2], 5, 5, 6);
128         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[3]",
129                 log.rttToAp.histogramNumPeersPerRequest[3], 6, 6, 1);
130 
131         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[0]",
132                 log.rttToAp.histogramRequestIntervalMs[0], 1, 10, 5);
133         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[1]",
134                 log.rttToAp.histogramRequestIntervalMs[1], 10, 100, 1);
135         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[2]",
136                 log.rttToAp.histogramRequestIntervalMs[2], 100, 1000, 1);
137         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[3]",
138                 log.rttToAp.histogramRequestIntervalMs[3], 1000, 10000, 1);
139         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[4]",
140                 log.rttToAp.histogramRequestIntervalMs[4], 100000, 1000000, 1);
141 
142         checkPeerStats("Sequence AP-only: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
143 
144         // mix of AP and Aware requests
145         WorkSource ws3 = new WorkSource(30);
146         ws3.add(20);
147         ws3.add(40);
148 
149         RangingRequest requestMixed03 = getDummyRangingRequest(0, 3);
150         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
151         RangingRequest requestMixed50 = getDummyRangingRequest(5, 0);
152         RangingRequest requestMixed08 = getDummyRangingRequest(0, 8);
153 
154         mDut.clear();
155         setTime(100);
156         mDut.recordRequest(ws3, requestMixed03);
157         setTime(101);
158         mDut.recordRequest(ws3, requestMixed25);
159         setTime(102);
160         mDut.recordRequest(ws3, requestMixed50);
161         setTime(103);
162         mDut.recordRequest(ws3, requestMixed08);
163 
164         log = mDut.consolidateProto();
165         checkMainStats("Sequence Mixed AP/Aware", log, 4, 0, 0, 0);
166 
167         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 2, 7, 3, 1, 2, 0, 0, 1);
168 
169         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramNumRequestsPerApp[0]",
170                 log.rttToAp.histogramNumRequestsPerApp[0], 1, 10, 3);
171 
172         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramNumPeersPerRequest[0]",
173                 log.rttToAp.histogramNumPeersPerRequest[0], 2, 2, 1);
174         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramNumPeersPerRequest[1]",
175                 log.rttToAp.histogramNumPeersPerRequest[1], 5, 5, 1);
176 
177         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramRequestIntervalMs[0]",
178                 log.rttToAp.histogramRequestIntervalMs[0], 1, 10, 1);
179 
180         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 3, 16, 3, 1, 3, 0, 0, 1);
181 
182         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramNumRequestsPerApp[0]",
183                 log.rttToAware.histogramNumRequestsPerApp[0], 1, 10, 3);
184 
185         validateProtoHistBucket(
186                 "Sequence Mixed AP/Aware: rttToAware.histogramNumPeersPerRequest[0]",
187                 log.rttToAware.histogramNumPeersPerRequest[0], 3, 3, 1);
188         validateProtoHistBucket(
189                 "Sequence Mixed AP/Aware: rttToAware.histogramNumPeersPerRequest[1]",
190                 log.rttToAware.histogramNumPeersPerRequest[1], 5, 5, 1);
191         validateProtoHistBucket(
192                 "Sequence Mixed AP/Aware: rttToAware.histogramNumPeersPerRequest[2]",
193                 log.rttToAware.histogramNumPeersPerRequest[2], 8, 8, 1);
194 
195         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramRequestIntervalMs[0]",
196                 log.rttToAware.histogramRequestIntervalMs[0], 1, 10, 2);
197     }
198 
199     /**
200      * Verify that recordResult() records valid metrics.
201      */
202     @Test
testRecordResult()203     public void testRecordResult() {
204         WifiMetricsProto.WifiRttLog log;
205 
206         // no requests
207         log = mDut.consolidateProto();
208         checkMainStats("No requests", log, 0, 0, 0, 0);
209         checkPeerStats("No requests: AP", log.rttToAp, 0, 0, 0, 0, 0, 0, 0, 0);
210         checkPeerStats("No requests: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
211 
212         // multiple AP results
213         RangingRequest requestAp1 = getDummyRangingRequest(1, 0);
214         RangingRequest requestAp2 = getDummyRangingRequest(2, 0);
215         RangingRequest requestAp5 = getDummyRangingRequest(5, 0);
216         RangingRequest requestAp6 = getDummyRangingRequest(6, 0);
217 
218         mDut.clear();
219         mDut.recordResult(requestAp1, getDummyRangingResults(RttNative.FRAMEWORK_RTT_STATUS_SUCCESS,
220                 requestAp1, 5, 0), 500);
221         mDut.recordResult(requestAp2, getDummyRangingResults(RttNative.FRAMEWORK_RTT_STATUS_SUCCESS,
222                 requestAp2, 10, 30), 1500);
223         mDut.recordResult(requestAp5, getDummyRangingResults(RttNative.FRAMEWORK_RTT_STATUS_SUCCESS,
224                 requestAp5, 0.3, -0.2), 700);
225         mDut.recordResult(requestAp6, getDummyRangingResults(RttNative.FRAMEWORK_RTT_STATUS_SUCCESS,
226                 requestAp6, 40, 30), 1800);
227         log = mDut.consolidateProto();
228 
229         checkMainStats("Sequence AP-only", log, 0, 0, 2, 0);
230         checkPeerStats("Sequence AP-only: AP", log.rttToAp, 0, 0, 0, 0, 0, 1, 6, 0);
231 
232         validateProtoHistBucket("Sequence AP-only: histogramMeasurementDurationApOnly[0]",
233                 log.histogramMeasurementDurationApOnly[0], Integer.MIN_VALUE, 1 * 1000, 2);
234         validateProtoHistBucket("Sequence AP-only: histogramMeasurementDurationApOnly[1]",
235                 log.histogramMeasurementDurationApOnly[1], 1 * 1000, 2 * 1000, 2);
236 
237         validateProtoIndividualStatusHistBucket(
238                 "Sequence AP-only: rttToAp.histogramIndividualStatus[0]",
239                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 14);
240 
241         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[0]",
242                 log.rttToAp.histogramDistance[0], Integer.MIN_VALUE, 0, 3);
243         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[1]",
244                 log.rttToAp.histogramDistance[1], 0, 5 * 1000, 2);
245         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[2]",
246                 log.rttToAp.histogramDistance[2], 5 * 1000, 15 * 1000, 2);
247         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[3]",
248                 log.rttToAp.histogramDistance[3], 30 * 1000, 60 * 1000, 2);
249         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[4]",
250                 log.rttToAp.histogramDistance[4], 60 * 1000, 100 * 1000, 1);
251         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[5]",
252                 log.rttToAp.histogramDistance[5], 100 * 1000, Integer.MAX_VALUE, 4);
253 
254         checkPeerStats("Sequence AP-only: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
255 
256         // mix of AP and Aware requests
257         RangingRequest requestMixed03 = getDummyRangingRequest(0, 3);
258         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
259         RangingRequest requestMixed50 = getDummyRangingRequest(5, 0);
260         RangingRequest requestMixed08 = getDummyRangingRequest(0, 8);
261 
262         mDut.clear();
263         mDut.recordResult(requestMixed03, getDummyRangingResults(
264                 RttNative.FRAMEWORK_RTT_STATUS_SUCCESS, requestMixed03, 5, 0), 6400);
265         mDut.recordResult(requestMixed25, getDummyRangingResults(
266                 RttNative.FRAMEWORK_RTT_STATUS_SUCCESS, requestMixed25, 10, 30), 7800);
267         mDut.recordResult(requestMixed50, getDummyRangingResults(
268                 RttNative.FRAMEWORK_RTT_STATUS_SUCCESS, requestMixed50, 0.3, -0.2), 3100);
269         mDut.recordResult(requestMixed08, getDummyRangingResults(
270                 RttNative.FRAMEWORK_RTT_STATUS_SUCCESS, requestMixed08, 40, 30), 9500);
271         log = mDut.consolidateProto();
272 
273         checkMainStats("Sequence Mixed AP/Aware", log, 0, 0, 1, 2);
274 
275         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 0, 0, 0, 0, 0, 1, 4, 0);
276 
277         validateProtoHistBucket("Sequence Mixed AP/Aware: histogramMeasurementDurationApOnly[0]",
278                 log.histogramMeasurementDurationApOnly[0], 3 * 1000, 4 * 1000, 1);
279         validateProtoHistBucket("Sequence Mixed AP/Aware: histogramMeasurementDurationWithAware[0]",
280                 log.histogramMeasurementDurationWithAware[0], 6 * 1000, 8 * 1000, 2);
281         validateProtoHistBucket("Sequence Mixed AP/Aware: histogramMeasurementDurationWithAware[1]",
282                 log.histogramMeasurementDurationWithAware[1], 8 * 1000, Integer.MAX_VALUE, 1);
283 
284         validateProtoIndividualStatusHistBucket(
285                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[0]",
286                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 7);
287 
288         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[0]",
289                 log.rttToAp.histogramDistance[0], Integer.MIN_VALUE, 0, 3);
290         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[1]",
291                 log.rttToAp.histogramDistance[1], 0, 5 * 1000, 2);
292         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[2]",
293                 log.rttToAp.histogramDistance[2], 5 * 1000, 15 * 1000, 1);
294         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[3]",
295                 log.rttToAp.histogramDistance[3], 30 * 1000, 60 * 1000, 1);
296 
297         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 0, 0, 0, 0, 0, 1, 4, 0);
298 
299         validateProtoIndividualStatusHistBucket(
300                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[0]",
301                 log.rttToAware.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS,
302                 16);
303 
304         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[0]",
305                 log.rttToAware.histogramDistance[0], 5 * 1000, 15 * 1000, 3);
306         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[1]",
307                 log.rttToAware.histogramDistance[1], 30 * 1000, 60 * 1000, 1);
308         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[2]",
309                 log.rttToAware.histogramDistance[2], 60 * 1000, 100 * 1000, 2);
310         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[3]",
311                 log.rttToAware.histogramDistance[3], 100 * 1000, Integer.MAX_VALUE, 10);
312     }
313 
314     /**
315      * Verify the behavior when the HAL returns with missing results or some results set to null.
316      */
317     @Test
testRecordMissingResults()318     public void testRecordMissingResults() {
319         WifiMetricsProto.WifiRttLog log;
320 
321         mDut.clear();
322         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
323         List<RangingResult> resultMixed25 = getDummyRangingResults(
324                 RttNative.FRAMEWORK_RTT_STATUS_SUCCESS, requestMixed25, 10, 30);
325         // remove some results
326         resultMixed25.remove(3); // Second Aware result: distance = 100
327         resultMixed25.remove(0); // First AP result: distance = 10
328         resultMixed25.add(null);
329         mDut.recordResult(requestMixed25, resultMixed25, 0);
330 
331         log = mDut.consolidateProto();
332 
333         checkMainStats("Sequence Mixed AP/Aware", log, 0, 0, 0, 1);
334 
335         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 0, 0, 0, 0, 0, 2, 1, 0);
336 
337         validateProtoIndividualStatusHistBucket(
338                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[0]",
339                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 1);
340         validateProtoIndividualStatusHistBucket(
341                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[1]",
342                 log.rttToAp.histogramIndividualStatus[1],
343                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 1);
344 
345         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[0]",
346                 log.rttToAp.histogramDistance[0], 30 * 1000, 60 * 1000, 1);
347 
348         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 0, 0, 0, 0, 0, 2, 2, 0);
349 
350         validateProtoIndividualStatusHistBucket(
351                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[0]",
352                 log.rttToAware.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS,
353                 4);
354         validateProtoIndividualStatusHistBucket(
355                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[1]",
356                 log.rttToAware.histogramIndividualStatus[1],
357                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 1);
358 
359         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[0]",
360                 log.rttToAware.histogramDistance[0], 60 * 1000, 100 * 1000, 1);
361         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[1]",
362                 log.rttToAware.histogramDistance[1], 100 * 1000, Integer.MAX_VALUE, 3);
363     }
364 
365     /**
366      * Verify the behavior when the HAL returns with NULL array.
367      */
368     @Test
testRecordNullArrayResults()369     public void testRecordNullArrayResults() {
370         WifiMetricsProto.WifiRttLog log;
371 
372         mDut.clear();
373         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
374         mDut.recordResult(requestMixed25, null, 0);
375 
376         log = mDut.consolidateProto();
377 
378         checkMainStats("Sequence Mixed AP/Aware", log, 0, 0, 0, 0);
379 
380         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 0, 0, 0, 0, 0, 1, 0, 0);
381 
382         validateProtoIndividualStatusHistBucket(
383                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[1]",
384                 log.rttToAp.histogramIndividualStatus[0],
385                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 2);
386 
387         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 0, 0, 0, 0, 0, 1, 0, 0);
388 
389         validateProtoIndividualStatusHistBucket(
390                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[0]",
391                 log.rttToAware.histogramIndividualStatus[0],
392                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 5);
393     }
394 
395     /**
396      * Verify that all individual status codes are translated correctly.
397      */
398     @Test
testRecordResultsStatuses()399     public void testRecordResultsStatuses() {
400         WifiMetricsProto.WifiRttLog log;
401 
402         mDut.clear();
403 
404         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_SUCCESS, 5);
405         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAILURE, 6);
406         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_NO_RSP, 7);
407         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_REJECTED, 8);
408         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_NOT_SCHEDULED_YET, 9);
409         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_TM_TIMEOUT, 10);
410         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL, 11);
411         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_NO_CAPABILITY, 12);
412         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_ABORTED, 13);
413         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_INVALID_TS, 14);
414         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_PROTOCOL, 15);
415         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_SCHEDULE, 16);
416         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_BUSY_TRY_LATER, 17);
417         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_INVALID_REQ, 18);
418         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_NO_WIFI, 19);
419         recordResultNTimes(RttNative.FRAMEWORK_RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE, 20);
420 
421         log = mDut.consolidateProto();
422 
423         collector.checkThat("AP histogramIndividualStatus.length",
424                 log.rttToAp.histogramIndividualStatus.length, equalTo(16));
425 
426         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[0]",
427                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 5);
428         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[1]",
429                 log.rttToAp.histogramIndividualStatus[1], WifiMetricsProto.WifiRttLog.FAILURE, 6);
430         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[2]",
431                 log.rttToAp.histogramIndividualStatus[2], WifiMetricsProto.WifiRttLog.FAIL_NO_RSP,
432                 7);
433         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[3]",
434                 log.rttToAp.histogramIndividualStatus[3], WifiMetricsProto.WifiRttLog.FAIL_REJECTED,
435                 8);
436         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[4]",
437                 log.rttToAp.histogramIndividualStatus[4],
438                 WifiMetricsProto.WifiRttLog.FAIL_NOT_SCHEDULED_YET, 9);
439         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[5]",
440                 log.rttToAp.histogramIndividualStatus[5],
441                 WifiMetricsProto.WifiRttLog.FAIL_TM_TIMEOUT, 10);
442         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[6]",
443                 log.rttToAp.histogramIndividualStatus[6],
444                 WifiMetricsProto.WifiRttLog.FAIL_AP_ON_DIFF_CHANNEL, 11);
445         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[7]",
446                 log.rttToAp.histogramIndividualStatus[7],
447                 WifiMetricsProto.WifiRttLog.FAIL_NO_CAPABILITY, 12);
448         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[8]",
449                 log.rttToAp.histogramIndividualStatus[8], WifiMetricsProto.WifiRttLog.ABORTED, 13);
450         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[9]",
451                 log.rttToAp.histogramIndividualStatus[9],
452                 WifiMetricsProto.WifiRttLog.FAIL_INVALID_TS, 14);
453         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[10]",
454                 log.rttToAp.histogramIndividualStatus[10],
455                 WifiMetricsProto.WifiRttLog.FAIL_PROTOCOL, 15);
456         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[11]",
457                 log.rttToAp.histogramIndividualStatus[11],
458                 WifiMetricsProto.WifiRttLog.FAIL_SCHEDULE, 16);
459         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[12]",
460                 log.rttToAp.histogramIndividualStatus[12],
461                 WifiMetricsProto.WifiRttLog.FAIL_BUSY_TRY_LATER, 17);
462         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[13]",
463                 log.rttToAp.histogramIndividualStatus[13], WifiMetricsProto.WifiRttLog.INVALID_REQ,
464                 18);
465         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[14]",
466                 log.rttToAp.histogramIndividualStatus[14], WifiMetricsProto.WifiRttLog.NO_WIFI, 19);
467         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[15]",
468                 log.rttToAp.histogramIndividualStatus[15],
469                 WifiMetricsProto.WifiRttLog.FAIL_FTM_PARAM_OVERRIDE, 20);
470 
471         collector.checkThat("Aware histogramIndividualStatus.length",
472                 log.rttToAware.histogramIndividualStatus.length, equalTo(0));
473     }
474 
475     /**
476      * Verify that all overall status codes are recorded correctly.
477      */
478     @Test
testRecordOverallStatus()479     public void testRecordOverallStatus() {
480         WifiMetricsProto.WifiRttLog log;
481 
482         mDut.clear();
483 
484         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_SUCCESS, 5);
485         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_FAIL, 6);
486         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_RTT_NOT_AVAILABLE, 7);
487         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_TIMEOUT, 8);
488         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_THROTTLE, 9);
489         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_HAL_FAILURE, 10);
490         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_AWARE_TRANSLATION_FAILURE,
491                 11);
492         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_LOCATION_PERMISSION_MISSING,
493                 12);
494 
495         log = mDut.consolidateProto();
496 
497         collector.checkThat("histogramOverallStatus.length", log.histogramOverallStatus.length,
498                 equalTo(8));
499 
500         validateProtoOverallStatusHistBucket("histogramOverallStatus[0]",
501                 log.histogramOverallStatus[0], WifiMetricsProto.WifiRttLog.OVERALL_SUCCESS, 5);
502         validateProtoOverallStatusHistBucket("histogramOverallStatus[1]",
503                 log.histogramOverallStatus[1], WifiMetricsProto.WifiRttLog.OVERALL_FAIL, 6);
504         validateProtoOverallStatusHistBucket("histogramOverallStatus[2]",
505                 log.histogramOverallStatus[2],
506                 WifiMetricsProto.WifiRttLog.OVERALL_RTT_NOT_AVAILABLE, 7);
507         validateProtoOverallStatusHistBucket("histogramOverallStatus[3]",
508                 log.histogramOverallStatus[3], WifiMetricsProto.WifiRttLog.OVERALL_TIMEOUT, 8);
509         validateProtoOverallStatusHistBucket("histogramOverallStatus[4]",
510                 log.histogramOverallStatus[4], WifiMetricsProto.WifiRttLog.OVERALL_THROTTLE, 9);
511         validateProtoOverallStatusHistBucket("histogramOverallStatus[5]",
512                 log.histogramOverallStatus[5], WifiMetricsProto.WifiRttLog.OVERALL_HAL_FAILURE, 10);
513         validateProtoOverallStatusHistBucket("histogramOverallStatus[6]",
514                 log.histogramOverallStatus[6],
515                 WifiMetricsProto.WifiRttLog.OVERALL_AWARE_TRANSLATION_FAILURE, 11);
516         validateProtoOverallStatusHistBucket("histogramOverallStatus[7]",
517                 log.histogramOverallStatus[7],
518                 WifiMetricsProto.WifiRttLog.OVERALL_LOCATION_PERMISSION_MISSING, 12);
519     }
520 
521     // Utilities
522 
523     /**
524      * Mock the elapsed time since boot to the input argument.
525      */
setTime(long timeMs)526     private void setTime(long timeMs) {
527         when(mClock.getElapsedSinceBootMillis()).thenReturn(timeMs);
528     }
529 
validateProtoHistBucket(String logPrefix, WifiMetricsProto.WifiRttLog.HistogramBucket bucket, long start, long end, int count)530     private void validateProtoHistBucket(String logPrefix,
531             WifiMetricsProto.WifiRttLog.HistogramBucket bucket, long start, long end, int count) {
532         collector.checkThat(logPrefix + ": start", bucket.start, equalTo(start));
533         collector.checkThat(logPrefix + ": end", bucket.end, equalTo(end));
534         collector.checkThat(logPrefix + ": count", bucket.count, equalTo(count));
535     }
536 
validateProtoOverallStatusHistBucket(String logPrefix, WifiMetricsProto.WifiRttLog.RttOverallStatusHistogramBucket bucket, int status, int count)537     private void validateProtoOverallStatusHistBucket(String logPrefix,
538             WifiMetricsProto.WifiRttLog.RttOverallStatusHistogramBucket bucket, int status,
539             int count) {
540         collector.checkThat(logPrefix + ": statusType", bucket.statusType, equalTo(status));
541         collector.checkThat(logPrefix + ": count", bucket.count, equalTo(count));
542     }
543 
validateProtoIndividualStatusHistBucket(String logPrefix, WifiMetricsProto.WifiRttLog.RttIndividualStatusHistogramBucket bucket, int status, int count)544     private void validateProtoIndividualStatusHistBucket(String logPrefix,
545             WifiMetricsProto.WifiRttLog.RttIndividualStatusHistogramBucket bucket, int status,
546             int count) {
547         collector.checkThat(logPrefix + ": statusType", bucket.statusType, equalTo(status));
548         collector.checkThat(logPrefix + ": count", bucket.count, equalTo(count));
549     }
550 
checkMainStats(String msgPrefix, WifiMetricsProto.WifiRttLog log, int numRequests, int histogramOverallStatusLength, int histogramMeasurementDurationApOnlyLength, int histogramMeasurementDurationWithAwareLength)551     private void checkMainStats(String msgPrefix, WifiMetricsProto.WifiRttLog log, int numRequests,
552             int histogramOverallStatusLength, int histogramMeasurementDurationApOnlyLength,
553             int histogramMeasurementDurationWithAwareLength) {
554         collector.checkThat(msgPrefix + ": numRequests", log.numRequests, equalTo(numRequests));
555         collector.checkThat(msgPrefix + ": histogramOverallStatus.length",
556                 log.histogramOverallStatus.length,
557                 equalTo(histogramOverallStatusLength));
558         collector.checkThat(msgPrefix + ": histogramMeasurementDurationApOnly.length",
559                 log.histogramMeasurementDurationApOnly.length,
560                 equalTo(histogramMeasurementDurationApOnlyLength));
561         collector.checkThat(msgPrefix + ": histogramMeasurementDurationWithAware.length",
562                 log.histogramMeasurementDurationWithAware.length,
563                 equalTo(histogramMeasurementDurationWithAwareLength));
564     }
565 
checkPeerStats(String msgPrefix, WifiMetricsProto.WifiRttLog.RttToPeerLog log, int numRequests, int numIndividualRequests, int numApps, int histogramNumRequestsPerAppLength, int histogramNumPeersPerRequestLength, int histogramIndividualStatusLength, int histogramDistanceLength, int histogramRequestIntervalMsLength)566     private void checkPeerStats(String msgPrefix, WifiMetricsProto.WifiRttLog.RttToPeerLog log,
567             int numRequests, int numIndividualRequests,
568             int numApps, int histogramNumRequestsPerAppLength,
569             int histogramNumPeersPerRequestLength, int histogramIndividualStatusLength,
570             int histogramDistanceLength, int histogramRequestIntervalMsLength) {
571         collector.checkThat(msgPrefix + ": numRequests", log.numRequests, equalTo(numRequests));
572         collector.checkThat(msgPrefix + ": numIndividualRequests", log.numIndividualRequests,
573                 equalTo(numIndividualRequests));
574         collector.checkThat(msgPrefix + ": numApps", log.numApps, equalTo(numApps));
575         collector.checkThat(msgPrefix + ": histogramNumRequestsPerApp.length",
576                 log.histogramNumRequestsPerApp.length, equalTo(histogramNumRequestsPerAppLength));
577         collector.checkThat(msgPrefix + ": histogramNumPeersPerRequest.length",
578                 log.histogramNumPeersPerRequest.length, equalTo(histogramNumPeersPerRequestLength));
579         collector.checkThat(msgPrefix + ": histogramIndividualStatus.length",
580                 log.histogramIndividualStatus.length, equalTo(histogramIndividualStatusLength));
581         collector.checkThat(msgPrefix + ": histogramDistance.length",
582                 log.histogramDistance.length, equalTo(histogramDistanceLength));
583         collector.checkThat(msgPrefix + ": histogramRequestIntervalMs.length",
584                 log.histogramRequestIntervalMs.length, equalTo(histogramRequestIntervalMsLength));
585     }
586 
getDummyRangingRequest(int countAp, int countAware)587     private RangingRequest getDummyRangingRequest(int countAp, int countAware) {
588         RangingRequest.Builder builder = new RangingRequest.Builder();
589         byte[] placeholderMacBase = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5};
590 
591         for (int i = 0; i < countAp; ++i) {
592             placeholderMacBase[0]++;
593             builder.addResponder(new ResponderConfig(MacAddress.fromBytes(placeholderMacBase),
594                     ResponderConfig.RESPONDER_AP, true, 0, 0, 0, 0, 0));
595         }
596         for (int i = 0; i < countAware; ++i) {
597             placeholderMacBase[0]++;
598             builder.addResponder(new ResponderConfig(MacAddress.fromBytes(placeholderMacBase),
599                     ResponderConfig.RESPONDER_AWARE, true, 0, 0, 0, 0, 0));
600         }
601 
602         return builder.build();
603     }
604 
getDummyRangingResults(int status, RangingRequest request, double baseDistanceM, double incrDistanceM)605     private List<RangingResult> getDummyRangingResults(int status, RangingRequest request,
606             double baseDistanceM, double incrDistanceM) {
607         List<RangingResult> rangingResults = new ArrayList<>();
608         double distance = baseDistanceM;
609 
610         for (ResponderConfig peer : request.mRttPeers) {
611 
612             RangingResult rttResult = new RangingResult(status, peer.macAddress,
613                     (int) (distance * 1000), 0, 0, 8, 8, null, null, null, 0, true);
614             distance += incrDistanceM;
615             rangingResults.add(rttResult);
616         }
617 
618         return rangingResults;
619     }
620 
recordResultNTimes(int status, int n)621     private void recordResultNTimes(int status, int n) {
622         RangingRequest request = getDummyRangingRequest(1, 0);
623         List<RangingResult> results = getDummyRangingResults(status, request, 0, 0);
624 
625         for (int i = 0; i < n; ++i) {
626             mDut.recordResult(request, results, 0);
627         }
628     }
629 
recordOverallStatusNTimes(int status, int n)630     private void recordOverallStatusNTimes(int status, int n) {
631         for (int i = 0; i < n; ++i) {
632             mDut.recordOverallStatus(status);
633         }
634     }
635 
dumpDut(String prefix)636     private void dumpDut(String prefix) {
637         StringWriter sw = new StringWriter();
638         mDut.dump(null, new PrintWriter(sw), null);
639         Log.e("RttMetrics", prefix + sw.toString());
640     }
641 }
642