1 /*
2 * Copyright 2022 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 #include "metrics_collector.h"
18
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 #include <unistd.h>
22
23 #include <cstdint>
24 #include <vector>
25
26 #include "os/metrics.h"
27 #include "types/raw_address.h"
28
29 using testing::_;
30 using testing::AnyNumber;
31 using testing::AtLeast;
32 using testing::AtMost;
33 using testing::DoAll;
34 using testing::Invoke;
35 using testing::Mock;
36 using testing::MockFunction;
37 using testing::NotNull;
38 using testing::Return;
39 using testing::SaveArg;
40 using testing::SetArgPointee;
41 using testing::Test;
42 using testing::WithArg;
43
44 int log_count = 0;
45 int32_t last_group_size;
46 int32_t last_group_metric_id;
47 int64_t last_connection_duration_nanos;
48 int64_t last_broadcast_duration_nanos;
49 std::vector<int64_t> last_device_connecting_offset_nanos;
50 std::vector<int64_t> last_device_connected_offset_nanos;
51 std::vector<int64_t> last_device_connection_duration_nanos;
52 std::vector<int32_t> last_device_connection_status;
53 std::vector<int32_t> last_device_disconnection_status;
54 std::vector<RawAddress> last_device_address;
55 std::vector<int64_t> last_streaming_offset_nanos;
56 std::vector<int64_t> last_streaming_duration_nanos;
57 std::vector<int32_t> last_streaming_context_type;
58
59 namespace bluetooth {
60 namespace os {
61
LogMetricLeAudioConnectionSessionReported(int32_t group_size,int32_t group_metric_id,int64_t connection_duration_nanos,const std::vector<int64_t> & device_connecting_offset_nanos,const std::vector<int64_t> & device_connected_offset_nanos,const std::vector<int64_t> & device_connection_duration_nanos,const std::vector<int32_t> & device_connection_status,const std::vector<int32_t> & device_disconnection_status,const std::vector<RawAddress> & device_address,const std::vector<int64_t> & streaming_offset_nanos,const std::vector<int64_t> & streaming_duration_nanos,const std::vector<int32_t> & streaming_context_type)62 void LogMetricLeAudioConnectionSessionReported(
63 int32_t group_size, int32_t group_metric_id, int64_t connection_duration_nanos,
64 const std::vector<int64_t>& device_connecting_offset_nanos,
65 const std::vector<int64_t>& device_connected_offset_nanos,
66 const std::vector<int64_t>& device_connection_duration_nanos,
67 const std::vector<int32_t>& device_connection_status,
68 const std::vector<int32_t>& device_disconnection_status,
69 const std::vector<RawAddress>& device_address,
70 const std::vector<int64_t>& streaming_offset_nanos,
71 const std::vector<int64_t>& streaming_duration_nanos,
72 const std::vector<int32_t>& streaming_context_type) {
73 log_count++;
74 last_group_size = group_size;
75 last_group_metric_id = group_metric_id;
76 last_connection_duration_nanos = connection_duration_nanos;
77 last_device_connecting_offset_nanos = device_connecting_offset_nanos;
78 last_device_connected_offset_nanos = device_connected_offset_nanos;
79 last_device_connection_duration_nanos = device_connection_duration_nanos;
80 last_device_connection_status = device_connection_status;
81 last_device_disconnection_status = device_disconnection_status;
82 last_device_address = device_address;
83 last_streaming_offset_nanos = streaming_offset_nanos;
84 last_streaming_duration_nanos = streaming_duration_nanos;
85 last_streaming_context_type = streaming_context_type;
86 }
87
LogMetricLeAudioBroadcastSessionReported(int64_t duration_nanos)88 void LogMetricLeAudioBroadcastSessionReported(int64_t duration_nanos) {
89 last_broadcast_duration_nanos = duration_nanos;
90 }
91
92 } // namespace os
93 } // namespace bluetooth
94
95 namespace bluetooth::le_audio {
96
97 const int32_t group_id1 = 1;
98 const RawAddress device1 = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66});
99
100 const int32_t group_id2 = 2;
101 const RawAddress device2 = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x67});
102 const RawAddress device3 = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x68});
103
104 class MockMetricsCollector : public MetricsCollector {
105 public:
MockMetricsCollector()106 MockMetricsCollector() {}
107 };
108
109 class MetricsCollectorTest : public Test {
110 protected:
111 std::unique_ptr<MetricsCollector> collector;
112
SetUp()113 void SetUp() override {
114 collector = std::make_unique<MockMetricsCollector>();
115
116 log_count = 0;
117 last_group_size = 0;
118 last_group_metric_id = 0;
119 last_broadcast_duration_nanos = 0;
120 last_connection_duration_nanos = 0;
121 last_device_connecting_offset_nanos = {};
122 last_device_connected_offset_nanos = {};
123 last_device_connection_duration_nanos = {};
124 last_device_connection_status = {};
125 last_device_disconnection_status = {};
126 last_device_address = {};
127 last_streaming_offset_nanos = {};
128 last_streaming_duration_nanos = {};
129 last_streaming_context_type = {};
130 }
131
TearDown()132 void TearDown() override { collector = nullptr; }
133 };
134
TEST_F(MetricsCollectorTest,Initialize)135 TEST_F(MetricsCollectorTest, Initialize) { ASSERT_EQ(log_count, 0); }
136
TEST_F(MetricsCollectorTest,ConnectionFailed)137 TEST_F(MetricsCollectorTest, ConnectionFailed) {
138 collector->OnConnectionStateChanged(group_id1, device1,
139 bluetooth::le_audio::ConnectionState::CONNECTING,
140 ConnectionStatus::UNKNOWN);
141 collector->OnConnectionStateChanged(group_id1, device1,
142 bluetooth::le_audio::ConnectionState::CONNECTED,
143 ConnectionStatus::FAILED);
144
145 ASSERT_EQ(log_count, 1);
146 ASSERT_EQ(last_group_metric_id, group_id1);
147 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
148 ASSERT_EQ(last_device_connection_status.size(), 1UL);
149 ASSERT_EQ(last_device_connection_status.back(), ConnectionStatus::FAILED);
150 }
151
TEST_F(MetricsCollectorTest,ConnectingConnectedDisconnected)152 TEST_F(MetricsCollectorTest, ConnectingConnectedDisconnected) {
153 collector->OnConnectionStateChanged(group_id1, device1,
154 bluetooth::le_audio::ConnectionState::CONNECTING,
155 ConnectionStatus::UNKNOWN);
156 collector->OnConnectionStateChanged(group_id1, device1,
157 bluetooth::le_audio::ConnectionState::CONNECTED,
158 ConnectionStatus::SUCCESS);
159 collector->OnConnectionStateChanged(group_id1, device1,
160 bluetooth::le_audio::ConnectionState::DISCONNECTED,
161 ConnectionStatus::SUCCESS);
162
163 ASSERT_EQ(log_count, 1);
164 ASSERT_EQ(last_group_metric_id, group_id1);
165 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
166 ASSERT_EQ(last_device_connection_status.size(), 1UL);
167 ASSERT_EQ(last_device_disconnection_status.size(), 1UL);
168 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
169 ASSERT_EQ(last_device_connected_offset_nanos.size(), 1UL);
170 ASSERT_EQ(last_device_connection_duration_nanos.size(), 1UL);
171 ASSERT_EQ(last_device_connection_status.back(), ConnectionStatus::SUCCESS);
172 ASSERT_EQ(last_device_disconnection_status.back(), ConnectionStatus::SUCCESS);
173 }
174
TEST_F(MetricsCollectorTest,SingleDeviceTwoConnections)175 TEST_F(MetricsCollectorTest, SingleDeviceTwoConnections) {
176 collector->OnConnectionStateChanged(group_id1, device1,
177 bluetooth::le_audio::ConnectionState::CONNECTING,
178 ConnectionStatus::UNKNOWN);
179 collector->OnConnectionStateChanged(group_id1, device1,
180 bluetooth::le_audio::ConnectionState::CONNECTED,
181 ConnectionStatus::SUCCESS);
182 collector->OnConnectionStateChanged(group_id1, device1,
183 bluetooth::le_audio::ConnectionState::DISCONNECTED,
184 ConnectionStatus::SUCCESS);
185
186 ASSERT_EQ(log_count, 1);
187 ASSERT_EQ(last_group_metric_id, group_id1);
188 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
189 ASSERT_EQ(last_device_connection_status.size(), 1UL);
190 ASSERT_EQ(last_device_disconnection_status.size(), 1UL);
191 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
192 ASSERT_EQ(last_device_connected_offset_nanos.size(), 1UL);
193 ASSERT_EQ(last_device_connection_duration_nanos.size(), 1UL);
194 ASSERT_EQ(last_device_connection_status.back(), ConnectionStatus::SUCCESS);
195 ASSERT_EQ(last_device_disconnection_status.back(), ConnectionStatus::SUCCESS);
196
197 collector->OnConnectionStateChanged(group_id1, device1,
198 bluetooth::le_audio::ConnectionState::CONNECTING,
199 ConnectionStatus::UNKNOWN);
200 collector->OnConnectionStateChanged(group_id1, device1,
201 bluetooth::le_audio::ConnectionState::CONNECTED,
202 ConnectionStatus::SUCCESS);
203 collector->OnConnectionStateChanged(group_id1, device1,
204 bluetooth::le_audio::ConnectionState::DISCONNECTED,
205 ConnectionStatus::SUCCESS);
206
207 ASSERT_EQ(log_count, 2);
208 ASSERT_EQ(last_group_metric_id, group_id1);
209 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
210 ASSERT_EQ(last_device_connection_status.size(), 1UL);
211 ASSERT_EQ(last_device_disconnection_status.size(), 1UL);
212 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
213 ASSERT_EQ(last_device_connected_offset_nanos.size(), 1UL);
214 ASSERT_EQ(last_device_connection_duration_nanos.size(), 1UL);
215 ASSERT_EQ(last_device_connection_status.back(), ConnectionStatus::SUCCESS);
216 ASSERT_EQ(last_device_disconnection_status.back(), ConnectionStatus::SUCCESS);
217 }
218
TEST_F(MetricsCollectorTest,StereoGroupBasicTest)219 TEST_F(MetricsCollectorTest, StereoGroupBasicTest) {
220 collector->OnConnectionStateChanged(group_id2, device2,
221 bluetooth::le_audio::ConnectionState::CONNECTING,
222 ConnectionStatus::UNKNOWN);
223 collector->OnConnectionStateChanged(group_id2, device2,
224 bluetooth::le_audio::ConnectionState::CONNECTED,
225 ConnectionStatus::SUCCESS);
226 collector->OnConnectionStateChanged(group_id2, device3,
227 bluetooth::le_audio::ConnectionState::CONNECTED,
228 ConnectionStatus::SUCCESS);
229 collector->OnConnectionStateChanged(group_id2, device3,
230 bluetooth::le_audio::ConnectionState::DISCONNECTED,
231 ConnectionStatus::SUCCESS);
232 collector->OnConnectionStateChanged(group_id2, device2,
233 bluetooth::le_audio::ConnectionState::DISCONNECTED,
234 ConnectionStatus::SUCCESS);
235
236 ASSERT_EQ(log_count, 1);
237 ASSERT_EQ(last_group_metric_id, group_id2);
238 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 2UL);
239 ASSERT_EQ(last_device_connection_status.size(), 2UL);
240 ASSERT_EQ(last_device_disconnection_status.size(), 2UL);
241 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 2UL);
242 ASSERT_EQ(last_device_connected_offset_nanos.size(), 2UL);
243 ASSERT_EQ(last_device_connection_duration_nanos.size(), 2UL);
244 }
245
TEST_F(MetricsCollectorTest,StereoGroupMultiReconnections)246 TEST_F(MetricsCollectorTest, StereoGroupMultiReconnections) {
247 collector->OnConnectionStateChanged(group_id2, device2,
248 bluetooth::le_audio::ConnectionState::CONNECTING,
249 ConnectionStatus::UNKNOWN);
250 collector->OnConnectionStateChanged(group_id2, device2,
251 bluetooth::le_audio::ConnectionState::CONNECTED,
252 ConnectionStatus::SUCCESS);
253 collector->OnConnectionStateChanged(group_id2, device3,
254 bluetooth::le_audio::ConnectionState::CONNECTED,
255 ConnectionStatus::SUCCESS);
256 collector->OnConnectionStateChanged(group_id2, device3,
257 bluetooth::le_audio::ConnectionState::DISCONNECTED,
258 ConnectionStatus::SUCCESS);
259 collector->OnConnectionStateChanged(group_id2, device3,
260 bluetooth::le_audio::ConnectionState::CONNECTED,
261 ConnectionStatus::SUCCESS);
262 collector->OnConnectionStateChanged(group_id2, device3,
263 bluetooth::le_audio::ConnectionState::DISCONNECTED,
264 ConnectionStatus::SUCCESS);
265 collector->OnConnectionStateChanged(group_id2, device2,
266 bluetooth::le_audio::ConnectionState::DISCONNECTED,
267 ConnectionStatus::SUCCESS);
268
269 ASSERT_EQ(log_count, 1);
270 ASSERT_EQ(last_group_metric_id, group_id2);
271 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 3UL);
272 ASSERT_EQ(last_device_connection_status.size(), 3UL);
273 ASSERT_EQ(last_device_disconnection_status.size(), 3UL);
274 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 3UL);
275 ASSERT_EQ(last_device_connected_offset_nanos.size(), 3UL);
276 ASSERT_EQ(last_device_connection_duration_nanos.size(), 3UL);
277 }
278
TEST_F(MetricsCollectorTest,MixGroups)279 TEST_F(MetricsCollectorTest, MixGroups) {
280 collector->OnConnectionStateChanged(group_id1, device1,
281 bluetooth::le_audio::ConnectionState::CONNECTING,
282 ConnectionStatus::UNKNOWN);
283 collector->OnConnectionStateChanged(group_id1, device1,
284 bluetooth::le_audio::ConnectionState::CONNECTED,
285 ConnectionStatus::SUCCESS);
286 collector->OnConnectionStateChanged(group_id2, device2,
287 bluetooth::le_audio::ConnectionState::CONNECTING,
288 ConnectionStatus::UNKNOWN);
289 collector->OnConnectionStateChanged(group_id2, device2,
290 bluetooth::le_audio::ConnectionState::CONNECTED,
291 ConnectionStatus::SUCCESS);
292 collector->OnConnectionStateChanged(group_id2, device3,
293 bluetooth::le_audio::ConnectionState::CONNECTED,
294 ConnectionStatus::SUCCESS);
295 collector->OnConnectionStateChanged(group_id2, device3,
296 bluetooth::le_audio::ConnectionState::DISCONNECTED,
297 ConnectionStatus::SUCCESS);
298 collector->OnConnectionStateChanged(group_id2, device2,
299 bluetooth::le_audio::ConnectionState::DISCONNECTED,
300 ConnectionStatus::SUCCESS);
301
302 ASSERT_EQ(log_count, 1);
303 ASSERT_EQ(last_group_metric_id, group_id2);
304 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 2UL);
305 ASSERT_EQ(last_device_connection_status.size(), 2UL);
306 ASSERT_EQ(last_device_disconnection_status.size(), 2UL);
307 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 2UL);
308 ASSERT_EQ(last_device_connected_offset_nanos.size(), 2UL);
309 ASSERT_EQ(last_device_connection_duration_nanos.size(), 2UL);
310
311 collector->OnConnectionStateChanged(group_id1, device1,
312 bluetooth::le_audio::ConnectionState::DISCONNECTED,
313 ConnectionStatus::SUCCESS);
314
315 ASSERT_EQ(log_count, 2);
316 ASSERT_EQ(last_group_metric_id, group_id1);
317 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
318 ASSERT_EQ(last_device_connection_status.size(), 1UL);
319 ASSERT_EQ(last_device_disconnection_status.size(), 1UL);
320 ASSERT_EQ(last_device_connecting_offset_nanos.size(), 1UL);
321 ASSERT_EQ(last_device_connected_offset_nanos.size(), 1UL);
322 ASSERT_EQ(last_device_connection_duration_nanos.size(), 1UL);
323 }
324
TEST_F(MetricsCollectorTest,GroupSizeUpdated)325 TEST_F(MetricsCollectorTest, GroupSizeUpdated) {
326 collector->OnGroupSizeUpdate(group_id2, 1);
327 collector->OnGroupSizeUpdate(group_id1, 2);
328 collector->OnConnectionStateChanged(group_id1, device1,
329 bluetooth::le_audio::ConnectionState::CONNECTING,
330 ConnectionStatus::UNKNOWN);
331 collector->OnConnectionStateChanged(group_id1, device1,
332 bluetooth::le_audio::ConnectionState::CONNECTED,
333 ConnectionStatus::SUCCESS);
334 collector->OnConnectionStateChanged(group_id1, device1,
335 bluetooth::le_audio::ConnectionState::DISCONNECTED,
336 ConnectionStatus::SUCCESS);
337
338 ASSERT_EQ(log_count, 1);
339 ASSERT_EQ(last_group_metric_id, group_id1);
340 ASSERT_EQ(last_group_size, 2);
341 }
342
TEST_F(MetricsCollectorTest,StreamingSessions)343 TEST_F(MetricsCollectorTest, StreamingSessions) {
344 collector->OnConnectionStateChanged(group_id1, device1,
345 bluetooth::le_audio::ConnectionState::CONNECTING,
346 ConnectionStatus::UNKNOWN);
347 collector->OnConnectionStateChanged(group_id1, device1,
348 bluetooth::le_audio::ConnectionState::CONNECTED,
349 ConnectionStatus::SUCCESS);
350 collector->OnStreamStarted(group_id1, bluetooth::le_audio::types::LeAudioContextType::MEDIA);
351 collector->OnStreamEnded(group_id1);
352 collector->OnStreamStarted(group_id1,
353 bluetooth::le_audio::types::LeAudioContextType::CONVERSATIONAL);
354 collector->OnStreamEnded(group_id1);
355 collector->OnConnectionStateChanged(group_id1, device1,
356 bluetooth::le_audio::ConnectionState::DISCONNECTED,
357 ConnectionStatus::SUCCESS);
358
359 ASSERT_EQ(log_count, 1);
360 ASSERT_EQ(last_group_metric_id, group_id1);
361 ASSERT_EQ(last_streaming_offset_nanos.size(), 2UL);
362 ASSERT_EQ(last_streaming_duration_nanos.size(), 2UL);
363 ASSERT_EQ(last_streaming_context_type.size(), 2UL);
364
365 ASSERT_GT(last_streaming_offset_nanos[0], 0L);
366 ASSERT_GT(last_streaming_offset_nanos[1], 0L);
367 ASSERT_GT(last_streaming_duration_nanos[0], 0L);
368 ASSERT_GT(last_streaming_duration_nanos[1], 0L);
369 ASSERT_EQ(last_streaming_context_type[0], static_cast<int32_t>(LeAudioMetricsContextType::MEDIA));
370 ASSERT_EQ(last_streaming_context_type[1],
371 static_cast<int32_t>(LeAudioMetricsContextType::COMMUNICATION));
372 }
373
TEST_F(MetricsCollectorTest,BroadastSessions)374 TEST_F(MetricsCollectorTest, BroadastSessions) {
375 last_broadcast_duration_nanos = 0;
376 collector->OnBroadcastStateChanged(true);
377 collector->OnBroadcastStateChanged(false);
378 ASSERT_GT(last_broadcast_duration_nanos, 0);
379 last_broadcast_duration_nanos = 0;
380 collector->OnBroadcastStateChanged(true);
381 collector->OnBroadcastStateChanged(false);
382 ASSERT_GT(last_broadcast_duration_nanos, 0);
383 }
384
385 } // namespace bluetooth::le_audio
386