1 /*
2 * Copyright (C) 2019 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 #define LOG_TAG "mediametrics_tests"
18 #include <utils/Log.h>
19
20 #include "MediaMetricsService.h"
21
22 #include <stdio.h>
23 #include <unordered_set>
24
25 #include <gtest/gtest.h>
26 #include <media/MediaMetricsItem.h>
27 #include <system/audio.h>
28
29 #include "AudioTypes.h"
30 #include "StringUtils.h"
31 #include "ValidateId.h"
32
33 using namespace android;
34
countNewlines(const char * s)35 static size_t countNewlines(const char *s) {
36 size_t count = 0;
37 while ((s = strchr(s, '\n')) != nullptr) {
38 ++s;
39 ++count;
40 }
41 return count;
42 }
43
44 template <typename M>
countDuplicates(const M & map)45 ssize_t countDuplicates(const M& map) {
46 std::unordered_set<typename M::mapped_type> s;
47 for (const auto &m : map) {
48 s.emplace(m.second);
49 }
50 return map.size() - s.size();
51 }
52
TEST(mediametrics_tests,startsWith)53 TEST(mediametrics_tests, startsWith) {
54 std::string s("test");
55 ASSERT_EQ(true, android::mediametrics::startsWith(s, "te"));
56 ASSERT_EQ(true, android::mediametrics::startsWith(s, std::string("tes")));
57 ASSERT_EQ(false, android::mediametrics::startsWith(s, "ts"));
58 ASSERT_EQ(false, android::mediametrics::startsWith(s, std::string("est")));
59 }
60
TEST(mediametrics_tests,defer)61 TEST(mediametrics_tests, defer) {
62 bool check = false;
63 {
64 android::mediametrics::Defer defer([&] { check = true; });
65 ASSERT_EQ(false, check);
66 }
67 ASSERT_EQ(true, check);
68 }
69
TEST(mediametrics_tests,shared_ptr_wrap)70 TEST(mediametrics_tests, shared_ptr_wrap) {
71 // Test shared pointer wrap with simple access
72 android::mediametrics::SharedPtrWrap<std::string> s("123");
73 ASSERT_EQ('1', s->at(0));
74 ASSERT_EQ('2', s->at(1));
75 s->push_back('4');
76 ASSERT_EQ('4', s->at(3));
77
78 const android::mediametrics::SharedPtrWrap<std::string> s2("345");
79 ASSERT_EQ('3', s2->operator[](0)); // s2[0] == '3'
80 // we allow modification through a const shared pointer wrap
81 // for compatibility with shared_ptr.
82 s2->push_back('6');
83 ASSERT_EQ('6', s2->operator[](3)); // s2[3] == '6'
84
85 android::mediametrics::SharedPtrWrap<std::string> s3("");
86 s3.set(std::make_shared<std::string>("abc"));
87 ASSERT_EQ('b', s3->operator[](1)); // s2[1] = 'b';
88
89 // Use Thunk to check whether the destructor was called prematurely
90 // when setting the shared ptr wrap in the middle of a method.
91
92 class Thunk {
93 std::function<void(int)> mF;
94 const int mFinal;
95
96 public:
97 explicit Thunk(decltype(mF) f, int final) : mF(std::move(f)), mFinal(final) {}
98 ~Thunk() { mF(mFinal); }
99 void thunk(int value) { mF(value); }
100 };
101
102 int counter = 0;
103 android::mediametrics::SharedPtrWrap<Thunk> s4(
104 [&](int value) {
105 s4.set(std::make_shared<Thunk>([](int){}, 0)); // recursively set s4 while in s4.
106 ++counter;
107 ASSERT_EQ(value, counter); // on thunk() value is 1, on destructor this is 2.
108 }, 2);
109
110 // This will fail if the shared ptr wrap doesn't hold a ref count during method access.
111 s4->thunk(1);
112 }
113
TEST(mediametrics_tests,lock_wrap)114 TEST(mediametrics_tests, lock_wrap) {
115 // Test lock wrap with simple access
116 android::mediametrics::LockWrap<std::string> s("123");
117 ASSERT_EQ('1', s->at(0));
118 ASSERT_EQ('2', s->at(1));
119 s->push_back('4');
120 ASSERT_EQ('4', s->at(3));
121
122 const android::mediametrics::LockWrap<std::string> s2("345");
123 ASSERT_EQ('3', s2->operator[](0)); // s2[0] == '3'
124 // note: we can't modify s2 due to const, s2->push_back('6');
125
126 android::mediametrics::LockWrap<std::string> s3("");
127 s3->operator=("abc");
128 ASSERT_EQ('b', s3->operator[](1)); // s2[1] = 'b';
129
130 // Check that we can recursively hold lock.
131 android::mediametrics::LockWrap<std::vector<int>> v{std::initializer_list<int>{1, 2}};
132 v->push_back(3);
133 v->push_back(4);
134 ASSERT_EQ(1, v->operator[](0));
135 ASSERT_EQ(2, v->operator[](1));
136 ASSERT_EQ(3, v->operator[](2));
137 ASSERT_EQ(4, v->operator[](3));
138 // The end of the full expression here requires recursive depth of 4.
139 ASSERT_EQ(10, v->operator[](0) + v->operator[](1) + v->operator[](2) + v->operator[](3));
140
141 // Mikhail's note: a non-recursive lock implementation could be used if one obtains
142 // the LockedPointer helper object like this and directly hold the lock through RAII,
143 // though it is trickier in use.
144 //
145 // We include an example here for completeness.
146 {
147 auto l = v.operator->();
148 ASSERT_EQ(10, l->operator[](0) + l->operator[](1) + l->operator[](2) + l->operator[](3));
149 }
150
151 // Use Thunk to check whether we have the lock when calling a method through LockWrap.
152
153 class Thunk {
154 std::function<void()> mF;
155
156 public:
157 explicit Thunk(decltype(mF) f) : mF(std::move(f)) {}
158 void thunk() { mF(); }
159 };
160
161 android::mediametrics::LockWrap<Thunk> s4([&]{
162 ASSERT_EQ((size_t)1, s4.getRecursionDepth()); // we must be locked when thunk() is called.
163 });
164
165 ASSERT_EQ((size_t)0, s4.getRecursionDepth());
166 // This will fail if we are not locked during method access.
167 s4->thunk();
168 ASSERT_EQ((size_t)0, s4.getRecursionDepth());
169 }
170
TEST(mediametrics_tests,lock_wrap_multithread)171 TEST(mediametrics_tests, lock_wrap_multithread) {
172 class Accumulator {
173 int32_t value_ = 0;
174 public:
175 void add(int32_t incr) {
176 const int32_t temp = value_;
177 sleep(0); // yield
178 value_ = temp + incr;
179 }
180 int32_t get() { return value_; }
181 };
182
183 android::mediametrics::LockWrap<Accumulator> a{}; // locked accumulator succeeds
184 // auto a = std::make_shared<Accumulator>(); // this fails, only 50% adds atomic.
185
186 constexpr size_t THREADS = 100;
187 constexpr size_t ITERATIONS = 10;
188 constexpr int32_t INCREMENT = 1;
189
190 std::vector<std::future<void>> threads(THREADS);
191 for (size_t i = 0; i < THREADS; ++i) {
192 threads.push_back(std::async(std::launch::async, [&] {
193 for (size_t j = 0; j < ITERATIONS; ++j) {
194 a->add(INCREMENT);
195 }
196 }));
197 }
198 threads.clear();
199
200 // If the add operations are not atomic, value will be smaller than expected.
201 ASSERT_EQ(INCREMENT * THREADS * ITERATIONS, (size_t)a->get());
202 }
203
TEST(mediametrics_tests,instantiate)204 TEST(mediametrics_tests, instantiate) {
205 sp mediaMetrics = new MediaMetricsService();
206 status_t status;
207
208 // random keys ignored when empty
209 std::unique_ptr<mediametrics::Item> random_key(mediametrics::Item::create("random_key"));
210 status = mediaMetrics->submit(random_key.get());
211 ASSERT_EQ(PERMISSION_DENIED, status);
212
213 // random keys ignored with data
214 random_key->setInt32("foo", 10);
215 status = mediaMetrics->submit(random_key.get());
216 ASSERT_EQ(PERMISSION_DENIED, status);
217
218 // known keys ignored if empty
219 std::unique_ptr<mediametrics::Item> audiotrack_key(mediametrics::Item::create("audiotrack"));
220 status = mediaMetrics->submit(audiotrack_key.get());
221 ASSERT_EQ(BAD_VALUE, status);
222
223 // known keys not ignored if not empty
224 audiotrack_key->addInt32("foo", 10);
225 status = mediaMetrics->submit(audiotrack_key.get());
226 ASSERT_EQ(NO_ERROR, status);
227
228
229 /*
230 // fluent style that goes directly to mediametrics
231 ASSERT_EQ(true, mediametrics::Item("audiorecord")
232 .setInt32("value", 2)
233 .addInt32("bar", 1)
234 .addInt32("value", 3)
235 .selfrecord());
236 */
237
238 mediaMetrics->dump(fileno(stdout), {} /* args */);
239 }
240
TEST(mediametrics_tests,package_installer_check)241 TEST(mediametrics_tests, package_installer_check) {
242 ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
243 "abcd", "installer")); // ok, package name has no dot.
244 ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
245 "android.com", "installer")); // ok, package name starts with android
246
247 ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
248 "abc.def", "com.android.foo")); // ok, installer name starts with com.android
249 ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
250 "123.456", "com.google.bar")); // ok, installer name starts with com.google
251 ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
252 "r2.d2", "preload")); // ok, installer name is preload
253
254 ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
255 "abc.def", "installer")); // unknown installer
256 ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
257 "123.456", "installer")); // unknown installer
258 ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
259 "r2.d2", "preload23")); // unknown installer
260
261 ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
262 "com.android.foo", "abc.def")); // unknown installer
263 ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
264 "com.google.bar", "123.456")); // unknown installer
265 }
266
TEST(mediametrics_tests,item_manipulation)267 TEST(mediametrics_tests, item_manipulation) {
268 mediametrics::Item item("audiorecord");
269
270 item.setInt32("value", 2).addInt32("bar", 3).addInt32("value", 4);
271
272 int32_t i32;
273 ASSERT_TRUE(item.getInt32("value", &i32));
274 ASSERT_EQ(6, i32);
275
276 ASSERT_TRUE(item.getInt32("bar", &i32));
277 ASSERT_EQ(3, i32);
278
279 item.setInt64("big", INT64_MAX).setInt64("smaller", INT64_MAX - 1).addInt64("smaller", -2);
280
281 int64_t i64;
282 ASSERT_TRUE(item.getInt64("big", &i64));
283 ASSERT_EQ(INT64_MAX, i64);
284
285 ASSERT_TRUE(item.getInt64("smaller", &i64));
286 ASSERT_EQ(INT64_MAX - 3, i64);
287
288 item.setDouble("precise", 10.5).setDouble("small", 0.125).addDouble("precise", 0.25);
289
290 double d;
291 ASSERT_TRUE(item.getDouble("precise", &d));
292 ASSERT_EQ(10.75, d);
293
294 ASSERT_TRUE(item.getDouble("small", &d));
295 ASSERT_EQ(0.125, d);
296
297 char *s;
298 item.setCString("name", "Frank").setCString("mother", "June").setCString("mother", "July");
299 ASSERT_TRUE(item.getCString("name", &s));
300 ASSERT_EQ(0, strcmp(s, "Frank"));
301 free(s);
302
303 ASSERT_TRUE(item.getCString("mother", &s));
304 ASSERT_EQ(0, strcmp(s, "July")); // "July" overwrites "June"
305 free(s);
306
307 item.setRate("burgersPerHour", 5, 2);
308 int64_t b, h;
309 ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
310 ASSERT_EQ(5, b);
311 ASSERT_EQ(2, h);
312 ASSERT_EQ(2.5, d);
313
314 item.addRate("burgersPerHour", 4, 2);
315 ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
316 ASSERT_EQ(9, b);
317 ASSERT_EQ(4, h);
318 ASSERT_EQ(2.25, d);
319
320 printf("item: %s\n", item.toString().c_str());
321 fflush(stdout);
322
323 sp mediaMetrics = new MediaMetricsService();
324 status_t status = mediaMetrics->submit(&item);
325 ASSERT_EQ(NO_ERROR, status);
326 mediaMetrics->dump(fileno(stdout), {} /* args */);
327 }
328
TEST(mediametrics_tests,superbig_item)329 TEST(mediametrics_tests, superbig_item) {
330 mediametrics::Item item("TheBigOne");
331 constexpr size_t count = 10000;
332
333 for (size_t i = 0; i < count; ++i) {
334 item.setInt32(std::to_string(i).c_str(), i);
335 }
336 for (size_t i = 0; i < count; ++i) {
337 int32_t i32;
338 ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
339 ASSERT_EQ((int32_t)i, i32);
340 }
341 }
342
TEST(mediametrics_tests,superbig_item_removal)343 TEST(mediametrics_tests, superbig_item_removal) {
344 mediametrics::Item item("TheOddBigOne");
345 constexpr size_t count = 10000;
346
347 for (size_t i = 0; i < count; ++i) {
348 item.setInt32(std::to_string(i).c_str(), i);
349 }
350 for (size_t i = 0; i < count; i += 2) {
351 item.filter(std::to_string(i).c_str()); // filter out all the evens.
352 }
353 for (size_t i = 0; i < count; ++i) {
354 int32_t i32;
355 if (i & 1) { // check to see that only the odds are left.
356 ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
357 ASSERT_EQ((int32_t)i, i32);
358 } else {
359 ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
360 }
361 }
362 }
363
TEST(mediametrics_tests,superbig_item_removal2)364 TEST(mediametrics_tests, superbig_item_removal2) {
365 mediametrics::Item item("TheOne");
366 constexpr size_t count = 10000;
367
368 for (size_t i = 0; i < count; ++i) {
369 item.setInt32(std::to_string(i).c_str(), i);
370 }
371 static const char *attrs[] = { "1", };
372 item.filterNot(1, attrs);
373
374 for (size_t i = 0; i < count; ++i) {
375 int32_t i32;
376 if (i == 1) { // check to see that there is only one
377 ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
378 ASSERT_EQ((int32_t)i, i32);
379 } else {
380 ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
381 }
382 }
383 }
384
TEST(mediametrics_tests,item_transmutation)385 TEST(mediametrics_tests, item_transmutation) {
386 mediametrics::Item item("Alchemist's Stone");
387
388 item.setInt64("convert", 123);
389 int64_t i64;
390 ASSERT_TRUE(item.getInt64("convert", &i64));
391 ASSERT_EQ(123, i64);
392
393 item.addInt32("convert", 2); // changes type of 'convert' from i64 to i32 (and re-init).
394 ASSERT_FALSE(item.getInt64("convert", &i64)); // should be false, no value in i64.
395
396 int32_t i32;
397 ASSERT_TRUE(item.getInt32("convert", &i32)); // check it is i32 and 2 (123 is discarded).
398 ASSERT_EQ(2, i32);
399 }
400
TEST(mediametrics_tests,item_binderization)401 TEST(mediametrics_tests, item_binderization) {
402 mediametrics::Item item;
403 item.setInt32("i32", 1)
404 .setInt64("i64", 2)
405 .setDouble("double", 3.1)
406 .setCString("string", "abc")
407 .setRate("rate", 11, 12);
408
409 Parcel p;
410 item.writeToParcel(&p);
411
412 p.setDataPosition(0); // rewind for reading
413 mediametrics::Item item2;
414 item2.readFromParcel(p);
415
416 ASSERT_EQ(item, item2);
417 }
418
TEST(mediametrics_tests,item_byteserialization)419 TEST(mediametrics_tests, item_byteserialization) {
420 mediametrics::Item item;
421 item.setInt32("i32", 1)
422 .setInt64("i64", 2)
423 .setDouble("double", 3.1)
424 .setCString("string", "abc")
425 .setRate("rate", 11, 12);
426
427 char *data;
428 size_t length;
429 ASSERT_EQ(0, item.writeToByteString(&data, &length));
430 ASSERT_GT(length, (size_t)0);
431
432 mediametrics::Item item2;
433 item2.readFromByteString(data, length);
434
435 printf("item: %s\n", item.toString().c_str());
436 printf("item2: %s\n", item2.toString().c_str());
437 ASSERT_EQ(item, item2);
438
439 free(data);
440 }
441
TEST(mediametrics_tests,item_iteration)442 TEST(mediametrics_tests, item_iteration) {
443 mediametrics::Item item;
444 item.setInt32("i32", 1)
445 .setInt64("i64", 2)
446 .setDouble("double", 3.125)
447 .setCString("string", "abc")
448 .setRate("rate", 11, 12);
449
450 int mask = 0;
451 for (auto &prop : item) {
452 const char *name = prop.getName();
453 if (!strcmp(name, "i32")) {
454 int32_t i32;
455 ASSERT_TRUE(prop.get(&i32));
456 ASSERT_EQ(1, i32);
457 ASSERT_EQ(1, std::get<int32_t>(prop.get()));
458 mask |= 1;
459 } else if (!strcmp(name, "i64")) {
460 int64_t i64;
461 ASSERT_TRUE(prop.get(&i64));
462 ASSERT_EQ(2, i64);
463 ASSERT_EQ(2, std::get<int64_t>(prop.get()));
464 mask |= 2;
465 } else if (!strcmp(name, "double")) {
466 double d;
467 ASSERT_TRUE(prop.get(&d));
468 ASSERT_EQ(3.125, d);
469 ASSERT_EQ(3.125, std::get<double>(prop.get()));
470 mask |= 4;
471 } else if (!strcmp(name, "string")) {
472 std::string s;
473 ASSERT_TRUE(prop.get(&s));
474 ASSERT_EQ("abc", s);
475 ASSERT_EQ(s, std::get<std::string>(prop.get()));
476 mask |= 8;
477 } else if (!strcmp(name, "rate")) {
478 std::pair<int64_t, int64_t> r;
479 ASSERT_TRUE(prop.get(&r));
480 ASSERT_EQ(11, r.first);
481 ASSERT_EQ(12, r.second);
482 ASSERT_EQ(r, std::get<decltype(r)>(prop.get()));
483 mask |= 16;
484 } else {
485 FAIL();
486 }
487 }
488 ASSERT_EQ(31, mask);
489 }
490
TEST(mediametrics_tests,item_expansion)491 TEST(mediametrics_tests, item_expansion) {
492 mediametrics::LogItem<1> item("I");
493 item.set("i32", (int32_t)1)
494 .set("i64", (int64_t)2)
495 .set("double", (double)3.125)
496 .set("string", "abcdefghijklmnopqrstuvwxyz")
497 .set("rate", std::pair<int64_t, int64_t>(11, 12));
498 ASSERT_TRUE(item.updateHeader());
499
500 mediametrics::Item item2;
501 item2.readFromByteString(item.getBuffer(), item.getLength());
502 ASSERT_EQ((pid_t)-1, item2.getPid());
503 ASSERT_EQ((uid_t)-1, item2.getUid());
504 int mask = 0;
505 for (auto &prop : item2) {
506 const char *name = prop.getName();
507 if (!strcmp(name, "i32")) {
508 int32_t i32;
509 ASSERT_TRUE(prop.get(&i32));
510 ASSERT_EQ(1, i32);
511 mask |= 1;
512 } else if (!strcmp(name, "i64")) {
513 int64_t i64;
514 ASSERT_TRUE(prop.get(&i64));
515 ASSERT_EQ(2, i64);
516 mask |= 2;
517 } else if (!strcmp(name, "double")) {
518 double d;
519 ASSERT_TRUE(prop.get(&d));
520 ASSERT_EQ(3.125, d);
521 mask |= 4;
522 } else if (!strcmp(name, "string")) {
523 std::string s;
524 ASSERT_TRUE(prop.get(&s));
525 ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
526 mask |= 8;
527 } else if (!strcmp(name, "rate")) {
528 std::pair<int64_t, int64_t> r;
529 ASSERT_TRUE(prop.get(&r));
530 ASSERT_EQ(11, r.first);
531 ASSERT_EQ(12, r.second);
532 mask |= 16;
533 } else {
534 FAIL();
535 }
536 }
537 ASSERT_EQ(31, mask);
538 }
539
TEST(mediametrics_tests,item_expansion2)540 TEST(mediametrics_tests, item_expansion2) {
541 mediametrics::LogItem<1> item("Bigly");
542 item.setPid(123)
543 .setUid(456);
544 constexpr size_t count = 10000;
545
546 for (size_t i = 0; i < count; ++i) {
547 // printf("recording %zu, %p, len:%zu of %zu remaining:%zu \n", i, item.getBuffer(), item.getLength(), item.getCapacity(), item.getRemaining());
548 item.set(std::to_string(i).c_str(), (int32_t)i);
549 }
550 ASSERT_TRUE(item.updateHeader());
551
552 mediametrics::Item item2;
553 printf("begin buffer:%p length:%zu\n", item.getBuffer(), item.getLength());
554 fflush(stdout);
555 item2.readFromByteString(item.getBuffer(), item.getLength());
556
557 ASSERT_EQ((pid_t)123, item2.getPid());
558 ASSERT_EQ((uid_t)456, item2.getUid());
559 for (size_t i = 0; i < count; ++i) {
560 int32_t i32;
561 ASSERT_TRUE(item2.getInt32(std::to_string(i).c_str(), &i32));
562 ASSERT_EQ((int32_t)i, i32);
563 }
564 }
565
TEST(mediametrics_tests,time_machine_storage)566 TEST(mediametrics_tests, time_machine_storage) {
567 auto item = std::make_shared<mediametrics::Item>("Key");
568 (*item).set("i32", (int32_t)1)
569 .set("i64", (int64_t)2)
570 .set("double", (double)3.125)
571 .set("string", "abcdefghijklmnopqrstuvwxyz")
572 .set("rate", std::pair<int64_t, int64_t>(11, 12));
573
574 // Let's put the item in
575 android::mediametrics::TimeMachine timeMachine;
576 ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
577
578 // Can we read the values?
579 int32_t i32;
580 ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "i32", &i32, -1));
581 ASSERT_EQ(1, i32);
582
583 int64_t i64;
584 ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "i64", &i64, -1));
585 ASSERT_EQ(2, i64);
586
587 double d;
588 ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "double", &d, -1));
589 ASSERT_EQ(3.125, d);
590
591 std::string s;
592 ASSERT_EQ(NO_ERROR, timeMachine.get("Key", "string", &s, -1));
593 ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
594
595 // Using fully qualified name?
596 i32 = 0;
597 ASSERT_EQ(NO_ERROR, timeMachine.get("Key.i32", &i32, -1));
598 ASSERT_EQ(1, i32);
599
600 i64 = 0;
601 ASSERT_EQ(NO_ERROR, timeMachine.get("Key.i64", &i64, -1));
602 ASSERT_EQ(2, i64);
603
604 d = 0.;
605 ASSERT_EQ(NO_ERROR, timeMachine.get("Key.double", &d, -1));
606 ASSERT_EQ(3.125, d);
607
608 s.clear();
609 ASSERT_EQ(NO_ERROR, timeMachine.get("Key.string", &s, -1));
610 ASSERT_EQ("abcdefghijklmnopqrstuvwxyz", s);
611 }
612
TEST(mediametrics_tests,time_machine_remote_key)613 TEST(mediametrics_tests, time_machine_remote_key) {
614 auto item = std::make_shared<mediametrics::Item>("Key1");
615 (*item).set("one", (int32_t)1)
616 .set("two", (int32_t)2);
617
618 android::mediametrics::TimeMachine timeMachine;
619 ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
620
621 auto item2 = std::make_shared<mediametrics::Item>("Key2");
622 (*item2).set("three", (int32_t)3)
623 .set("[Key1]four", (int32_t)4) // affects Key1
624 .set("[Key1]five", (int32_t)5); // affects key1
625
626 ASSERT_EQ(NO_ERROR, timeMachine.put(item2, true));
627
628 auto item3 = std::make_shared<mediametrics::Item>("Key2");
629 (*item3).set("six", (int32_t)6)
630 .set("[Key1]seven", (int32_t)7); // affects Key1
631
632 ASSERT_EQ(NO_ERROR, timeMachine.put(item3, false)); // remote keys not allowed.
633
634 // Can we read the values?
635 int32_t i32;
636 ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.one", &i32, -1));
637 ASSERT_EQ(1, i32);
638
639 ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.two", &i32, -1));
640 ASSERT_EQ(2, i32);
641
642 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.three", &i32, -1));
643
644 ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.three", &i32, -1));
645 ASSERT_EQ(3, i32);
646
647 ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.four", &i32, -1));
648 ASSERT_EQ(4, i32);
649
650 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.four", &i32, -1));
651
652 ASSERT_EQ(NO_ERROR, timeMachine.get("Key1.five", &i32, -1));
653 ASSERT_EQ(5, i32);
654
655 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.five", &i32, -1));
656
657 ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.six", &i32, -1));
658 ASSERT_EQ(6, i32);
659
660 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key2.seven", &i32, -1));
661 }
662
TEST(mediametrics_tests,time_machine_gc)663 TEST(mediametrics_tests, time_machine_gc) {
664 auto item = std::make_shared<mediametrics::Item>("Key1");
665 (*item).set("one", (int32_t)1)
666 .set("two", (int32_t)2)
667 .setTimestamp(10);
668
669 android::mediametrics::TimeMachine timeMachine(1, 2); // keep at most 2 keys.
670
671 ASSERT_EQ((size_t)0, timeMachine.size());
672
673 ASSERT_EQ(NO_ERROR, timeMachine.put(item, true));
674
675 ASSERT_EQ((size_t)1, timeMachine.size());
676
677 auto item2 = std::make_shared<mediametrics::Item>("Key2");
678 (*item2).set("three", (int32_t)3)
679 .set("[Key1]three", (int32_t)3)
680 .setTimestamp(11);
681
682 ASSERT_EQ(NO_ERROR, timeMachine.put(item2, true));
683 ASSERT_EQ((size_t)2, timeMachine.size());
684
685 //printf("Before\n%s\n\n", timeMachine.dump().c_str());
686
687 auto item3 = std::make_shared<mediametrics::Item>("Key3");
688 (*item3).set("six", (int32_t)6)
689 .set("[Key1]four", (int32_t)4) // affects Key1
690 .set("[Key1]five", (int32_t)5) // affects key1
691 .setTimestamp(12);
692
693 ASSERT_EQ(NO_ERROR, timeMachine.put(item3, true));
694
695 ASSERT_EQ((size_t)2, timeMachine.size());
696
697 // Can we read the values?
698 int32_t i32;
699 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.one", &i32, -1));
700 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.two", &i32, -1));
701 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.three", &i32, -1));
702 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.four", &i32, -1));
703 ASSERT_EQ(BAD_VALUE, timeMachine.get("Key1.five", &i32, -1));
704
705 ASSERT_EQ(NO_ERROR, timeMachine.get("Key2.three", &i32, -1));
706 ASSERT_EQ(3, i32);
707
708 ASSERT_EQ(NO_ERROR, timeMachine.get("Key3.six", &i32, -1));
709 ASSERT_EQ(6, i32);
710
711 printf("After\n%s\n", timeMachine.dump().first.c_str());
712 }
713
TEST(mediametrics_tests,transaction_log_gc)714 TEST(mediametrics_tests, transaction_log_gc) {
715 auto item = std::make_shared<mediametrics::Item>("Key1");
716 (*item).set("one", (int32_t)1)
717 .set("two", (int32_t)2)
718 .setTimestamp(10);
719
720 android::mediametrics::TransactionLog transactionLog(1, 2); // keep at most 2 items
721 ASSERT_EQ((size_t)0, transactionLog.size());
722
723 ASSERT_EQ(NO_ERROR, transactionLog.put(item));
724 ASSERT_EQ((size_t)1, transactionLog.size());
725
726 auto item2 = std::make_shared<mediametrics::Item>("Key2");
727 (*item2).set("three", (int32_t)3)
728 .set("[Key1]three", (int32_t)3)
729 .setTimestamp(11);
730
731 ASSERT_EQ(NO_ERROR, transactionLog.put(item2));
732 ASSERT_EQ((size_t)2, transactionLog.size());
733
734 auto item3 = std::make_shared<mediametrics::Item>("Key3");
735 (*item3).set("six", (int32_t)6)
736 .set("[Key1]four", (int32_t)4) // affects Key1
737 .set("[Key1]five", (int32_t)5) // affects key1
738 .setTimestamp(12);
739
740 ASSERT_EQ(NO_ERROR, transactionLog.put(item3));
741 ASSERT_EQ((size_t)2, transactionLog.size());
742 }
743
TEST(mediametrics_tests,analytics_actions)744 TEST(mediametrics_tests, analytics_actions) {
745 mediametrics::AnalyticsActions analyticsActions;
746 bool action1 = false;
747 bool action2 = false;
748 bool action3 = false;
749 bool action4 = false;
750
751 // check to see whether various actions have been matched.
752 analyticsActions.addAction(
753 "audio.flinger.event",
754 std::string("AudioFlinger"),
755 std::make_shared<mediametrics::AnalyticsActions::Function>(
756 [&](const std::shared_ptr<const android::mediametrics::Item> &) {
757 action1 = true;
758 }));
759
760 analyticsActions.addAction(
761 "audio.*.event",
762 std::string("AudioFlinger"),
763 std::make_shared<mediametrics::AnalyticsActions::Function>(
764 [&](const std::shared_ptr<const android::mediametrics::Item> &) {
765 action2 = true;
766 }));
767
768 analyticsActions.addAction("audio.fl*n*g*r.event",
769 std::string("AudioFlinger"),
770 std::make_shared<mediametrics::AnalyticsActions::Function>(
771 [&](const std::shared_ptr<const android::mediametrics::Item> &) {
772 action3 = true;
773 }));
774
775 analyticsActions.addAction("audio.fl*gn*r.event",
776 std::string("AudioFlinger"),
777 std::make_shared<mediametrics::AnalyticsActions::Function>(
778 [&](const std::shared_ptr<const android::mediametrics::Item> &) {
779 action4 = true;
780 }));
781
782 // make a test item
783 auto item = std::make_shared<mediametrics::Item>("audio.flinger");
784 (*item).set("event", "AudioFlinger");
785
786 // get the actions and execute them
787 auto actions = analyticsActions.getActionsForItem(item);
788 for (const auto& action : actions) {
789 action->operator()(item);
790 }
791
792 // The following should match.
793 ASSERT_EQ(true, action1);
794 ASSERT_EQ(true, action2);
795 ASSERT_EQ(true, action3);
796 ASSERT_EQ(false, action4); // audio.fl*gn*r != audio.flinger
797 }
798
TEST(mediametrics_tests,audio_analytics_permission)799 TEST(mediametrics_tests, audio_analytics_permission) {
800 auto item = std::make_shared<mediametrics::Item>("audio.1");
801 (*item).set("one", (int32_t)1)
802 .set("two", (int32_t)2)
803 .setTimestamp(10);
804
805 auto item2 = std::make_shared<mediametrics::Item>("audio.1");
806 (*item2).set("three", (int32_t)3)
807 .setTimestamp(11);
808
809 auto item3 = std::make_shared<mediametrics::Item>("audio.2");
810 (*item3).set("four", (int32_t)4)
811 .setTimestamp(12);
812
813 std::shared_ptr<mediametrics::StatsdLog> statsdLog =
814 std::make_shared<mediametrics::StatsdLog>(10);
815 android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
816
817 // untrusted entities cannot create a new key.
818 ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item, false /* isTrusted */));
819 ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item2, false /* isTrusted */));
820
821 // TODO: Verify contents of AudioAnalytics.
822 // Currently there is no getter API in AudioAnalytics besides dump.
823 ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
824
825 ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
826 // untrusted entities can add to an existing key
827 ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
828
829 // Check that we have some info in the dump.
830 ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
831 }
832
TEST(mediametrics_tests,audio_analytics_permission2)833 TEST(mediametrics_tests, audio_analytics_permission2) {
834 constexpr int32_t transactionUid = 1010; // arbitrary
835 auto item = std::make_shared<mediametrics::Item>("audio.1");
836 (*item).set("one", (int32_t)1)
837 .set("two", (int32_t)2)
838 .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
839 .setTimestamp(10);
840
841 // item2 submitted untrusted
842 auto item2 = std::make_shared<mediametrics::Item>("audio.1");
843 (*item2).set("three", (int32_t)3)
844 .setUid(transactionUid)
845 .setTimestamp(11);
846
847 auto item3 = std::make_shared<mediametrics::Item>("audio.2");
848 (*item3).set("four", (int32_t)4)
849 .setTimestamp(12);
850
851 std::shared_ptr<mediametrics::StatsdLog> statsdLog =
852 std::make_shared<mediametrics::StatsdLog>(10);
853 android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
854
855 // untrusted entities cannot create a new key.
856 ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item, false /* isTrusted */));
857 ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item2, false /* isTrusted */));
858
859 // TODO: Verify contents of AudioAnalytics.
860 // Currently there is no getter API in AudioAnalytics besides dump.
861 ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
862
863 ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
864 // untrusted entities can add to an existing key
865 ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
866
867 // Check that we have some info in the dump.
868 ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
869 }
870
TEST(mediametrics_tests,audio_analytics_dump)871 TEST(mediametrics_tests, audio_analytics_dump) {
872 auto item = std::make_shared<mediametrics::Item>("audio.1");
873 (*item).set("one", (int32_t)1)
874 .set("two", (int32_t)2)
875 .setTimestamp(10);
876
877 auto item2 = std::make_shared<mediametrics::Item>("audio.1");
878 (*item2).set("three", (int32_t)3)
879 .setTimestamp(11);
880
881 auto item3 = std::make_shared<mediametrics::Item>("audio.2");
882 (*item3).set("four", (int32_t)4)
883 .setTimestamp(12);
884
885 std::shared_ptr<mediametrics::StatsdLog> statsdLog =
886 std::make_shared<mediametrics::StatsdLog>(10);
887 android::mediametrics::AudioAnalytics audioAnalytics{statsdLog};
888
889 ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
890 // untrusted entities can add to an existing key
891 ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
892 ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item3, true /* isTrusted */));
893
894 // find out how many lines we have.
895 auto [string, lines] = audioAnalytics.dump(1000);
896 ASSERT_EQ(lines, (int32_t) countNewlines(string.c_str()));
897
898 printf("AudioAnalytics: %s", string.c_str());
899 // ensure that dump operates over those lines.
900 for (int32_t ll = 0; ll < lines; ++ll) {
901 auto [s, l] = audioAnalytics.dump(ll);
902 ASSERT_EQ(ll, l);
903 ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
904 }
905 }
906
TEST(mediametrics_tests,device_parsing)907 TEST(mediametrics_tests, device_parsing) {
908 auto devaddr = android::mediametrics::stringutils::getDeviceAddressPairs("(DEVICE, )");
909 ASSERT_EQ((size_t)1, devaddr.size());
910 ASSERT_EQ("DEVICE", devaddr[0].first);
911 ASSERT_EQ("", devaddr[0].second);
912
913 devaddr = android::mediametrics::stringutils::getDeviceAddressPairs(
914 "(DEVICE1, A)|(D, ADDRB)");
915 ASSERT_EQ((size_t)2, devaddr.size());
916 ASSERT_EQ("DEVICE1", devaddr[0].first);
917 ASSERT_EQ("A", devaddr[0].second);
918 ASSERT_EQ("D", devaddr[1].first);
919 ASSERT_EQ("ADDRB", devaddr[1].second);
920
921 devaddr = android::mediametrics::stringutils::getDeviceAddressPairs(
922 "(A,B)|(C,D)");
923 ASSERT_EQ((size_t)2, devaddr.size());
924 ASSERT_EQ("A", devaddr[0].first);
925 ASSERT_EQ("B", devaddr[0].second);
926 ASSERT_EQ("C", devaddr[1].first);
927 ASSERT_EQ("D", devaddr[1].second);
928
929 devaddr = android::mediametrics::stringutils::getDeviceAddressPairs(
930 " ( A1 , B ) | ( C , D2 ) ");
931 ASSERT_EQ((size_t)2, devaddr.size());
932 ASSERT_EQ("A1", devaddr[0].first);
933 ASSERT_EQ("B", devaddr[0].second);
934 ASSERT_EQ("C", devaddr[1].first);
935 ASSERT_EQ("D2", devaddr[1].second);
936 }
937
TEST(mediametrics_tests,timed_action)938 TEST(mediametrics_tests, timed_action) {
939 android::mediametrics::TimedAction timedAction;
940 std::atomic_int value1 = 0;
941
942 timedAction.postIn(std::chrono::seconds(0), [&value1] { ++value1; });
943 timedAction.postIn(std::chrono::seconds(1000), [&value1] { ++value1; });
944 usleep(100000);
945 ASSERT_EQ(1, value1);
946 ASSERT_EQ((size_t)1, timedAction.size());
947 }
948
949 // Ensure we don't introduce unexpected duplicates into our maps.
TEST(mediametrics_tests,audio_types_tables)950 TEST(mediametrics_tests, audio_types_tables) {
951 using namespace android::mediametrics::types;
952
953 ASSERT_EQ(0, countDuplicates(getAudioCallerNameMap()));
954 ASSERT_EQ(2, countDuplicates(getAudioDeviceInMap())); // has dups
955 ASSERT_EQ(1, countDuplicates(getAudioDeviceOutMap())); // has dups
956 ASSERT_EQ(0, countDuplicates(getAudioThreadTypeMap()));
957 ASSERT_EQ(0, countDuplicates(getAudioTrackTraitsMap()));
958 }
959
960 // Check our string validation (before logging to statsd).
961 // This variant checks the logged, possibly shortened string.
TEST(mediametrics_tests,audio_types_string)962 TEST(mediametrics_tests, audio_types_string) {
963 using namespace android::mediametrics::types;
964
965 ASSERT_EQ("java", (lookup<CALLER_NAME, std::string>)("java"));
966 ASSERT_EQ("", (lookup<CALLER_NAME, std::string>)("random"));
967
968 ASSERT_EQ("SPEECH", (lookup<CONTENT_TYPE, std::string>)("AUDIO_CONTENT_TYPE_SPEECH"));
969 ASSERT_EQ("", (lookup<CONTENT_TYPE, std::string>)("random"));
970
971 ASSERT_EQ("FLAC", (lookup<ENCODING, std::string>)("AUDIO_FORMAT_FLAC"));
972 ASSERT_EQ("", (lookup<ENCODING, std::string>)("random"));
973
974 ASSERT_EQ("USB_DEVICE", (lookup<INPUT_DEVICE, std::string>)("AUDIO_DEVICE_IN_USB_DEVICE"));
975 ASSERT_EQ("BUILTIN_MIC|WIRED_HEADSET", (lookup<INPUT_DEVICE, std::string>)(
976 "AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET"));
977 ASSERT_EQ("", (lookup<INPUT_DEVICE, std::string>)("random"));
978
979 ASSERT_EQ("RAW", (lookup<INPUT_FLAG, std::string>)("AUDIO_INPUT_FLAG_RAW"));
980 ASSERT_EQ("HW_AV_SYNC|VOIP_TX", (lookup<INPUT_FLAG, std::string>)(
981 "AUDIO_INPUT_FLAG_HW_AV_SYNC|AUDIO_INPUT_FLAG_VOIP_TX"));
982 ASSERT_EQ("", (lookup<INPUT_FLAG, std::string>)("random"));
983
984 ASSERT_EQ("BLUETOOTH_SCO_CARKIT",
985 (lookup<OUTPUT_DEVICE, std::string>)("AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"));
986 ASSERT_EQ("SPEAKER|HDMI", (lookup<OUTPUT_DEVICE, std::string>)(
987 "AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI"));
988 ASSERT_EQ("", (lookup<OUTPUT_DEVICE, std::string>)("random"));
989
990 ASSERT_EQ("PRIMARY", (lookup<OUTPUT_FLAG, std::string>)("AUDIO_OUTPUT_FLAG_PRIMARY"));
991 ASSERT_EQ("DEEP_BUFFER|NON_BLOCKING", (lookup<OUTPUT_FLAG, std::string>)(
992 "AUDIO_OUTPUT_FLAG_DEEP_BUFFER|AUDIO_OUTPUT_FLAG_NON_BLOCKING"));
993 ASSERT_EQ("", (lookup<OUTPUT_FLAG, std::string>)("random"));
994
995 ASSERT_EQ("MIC", (lookup<SOURCE_TYPE, std::string>)("AUDIO_SOURCE_MIC"));
996 ASSERT_EQ("", (lookup<SOURCE_TYPE, std::string>)("random"));
997
998 ASSERT_EQ("TTS", (lookup<STREAM_TYPE, std::string>)("AUDIO_STREAM_TTS"));
999 ASSERT_EQ("", (lookup<STREAM_TYPE, std::string>)("random"));
1000
1001 ASSERT_EQ("DIRECT", (lookup<THREAD_TYPE, std::string>)("DIRECT"));
1002 ASSERT_EQ("", (lookup<THREAD_TYPE, std::string>)("random"));
1003
1004 ASSERT_EQ("static", (lookup<TRACK_TRAITS, std::string>)("static"));
1005 ASSERT_EQ("", (lookup<TRACK_TRAITS, std::string>)("random"));
1006
1007 ASSERT_EQ("VOICE_COMMUNICATION",
1008 (lookup<USAGE, std::string>)("AUDIO_USAGE_VOICE_COMMUNICATION"));
1009 ASSERT_EQ("", (lookup<USAGE, std::string>)("random"));
1010 }
1011
1012 // Check our string validation (before logging to statsd).
1013 // This variant checks integral value logging.
TEST(mediametrics_tests,audio_types_integer)1014 TEST(mediametrics_tests, audio_types_integer) {
1015 using namespace android::mediametrics::types;
1016
1017 ASSERT_EQ(2, (lookup<CALLER_NAME, int32_t>)("java"));
1018 ASSERT_EQ(0, (lookup<CALLER_NAME, int32_t>)("random")); // 0 == unknown
1019
1020 ASSERT_EQ((int32_t)AUDIO_CONTENT_TYPE_SPEECH,
1021 (lookup<CONTENT_TYPE, int32_t>)("AUDIO_CONTENT_TYPE_SPEECH"));
1022 ASSERT_EQ((int32_t)AUDIO_CONTENT_TYPE_UNKNOWN, (lookup<CONTENT_TYPE, int32_t>)("random"));
1023
1024 ASSERT_EQ((int32_t)AUDIO_FORMAT_FLAC, (lookup<ENCODING, int32_t>)("AUDIO_FORMAT_FLAC"));
1025 ASSERT_EQ((int32_t)AUDIO_FORMAT_INVALID, (lookup<ENCODING, int32_t>)("random"));
1026
1027 ASSERT_EQ(getAudioDeviceInMap().at("AUDIO_DEVICE_IN_USB_DEVICE"),
1028 (lookup<INPUT_DEVICE, int64_t>)("AUDIO_DEVICE_IN_USB_DEVICE"));
1029 ASSERT_EQ(getAudioDeviceInMap().at("AUDIO_DEVICE_IN_BUILTIN_MIC")
1030 | getAudioDeviceInMap().at("AUDIO_DEVICE_IN_WIRED_HEADSET"),
1031 (lookup<INPUT_DEVICE, int64_t>)(
1032 "AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_WIRED_HEADSET"));
1033 ASSERT_EQ(0, (lookup<INPUT_DEVICE, int64_t>)("random"));
1034
1035 ASSERT_EQ((int32_t)AUDIO_INPUT_FLAG_RAW,
1036 (lookup<INPUT_FLAG, int32_t>)("AUDIO_INPUT_FLAG_RAW"));
1037 ASSERT_EQ((int32_t)AUDIO_INPUT_FLAG_HW_AV_SYNC
1038 | (int32_t)AUDIO_INPUT_FLAG_VOIP_TX,
1039 (lookup<INPUT_FLAG, int32_t>)(
1040 "AUDIO_INPUT_FLAG_HW_AV_SYNC|AUDIO_INPUT_FLAG_VOIP_TX"));
1041 ASSERT_EQ(0, (lookup<INPUT_FLAG, int32_t>)("random"));
1042
1043 ASSERT_EQ(getAudioDeviceOutMap().at("AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"),
1044 (lookup<OUTPUT_DEVICE, int64_t>)("AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"));
1045 ASSERT_EQ(getAudioDeviceOutMap().at("AUDIO_DEVICE_OUT_SPEAKER")
1046 | getAudioDeviceOutMap().at("AUDIO_DEVICE_OUT_HDMI"),
1047 (lookup<OUTPUT_DEVICE, int64_t>)(
1048 "AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI"));
1049 ASSERT_EQ(0, (lookup<OUTPUT_DEVICE, int64_t>)("random"));
1050
1051 ASSERT_EQ((int32_t)AUDIO_OUTPUT_FLAG_PRIMARY,
1052 (lookup<OUTPUT_FLAG, int32_t>)("AUDIO_OUTPUT_FLAG_PRIMARY"));
1053 ASSERT_EQ((int32_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER | (int32_t)AUDIO_OUTPUT_FLAG_NON_BLOCKING,
1054 (lookup<OUTPUT_FLAG, int32_t>)(
1055 "AUDIO_OUTPUT_FLAG_DEEP_BUFFER|AUDIO_OUTPUT_FLAG_NON_BLOCKING"));
1056 ASSERT_EQ(0, (lookup<OUTPUT_FLAG, int32_t>)("random"));
1057
1058 ASSERT_EQ((int32_t)AUDIO_SOURCE_MIC, (lookup<SOURCE_TYPE, int32_t>)("AUDIO_SOURCE_MIC"));
1059 ASSERT_EQ((int32_t)AUDIO_SOURCE_DEFAULT, (lookup<SOURCE_TYPE, int32_t>)("random"));
1060
1061 ASSERT_EQ((int32_t)AUDIO_STREAM_TTS, (lookup<STREAM_TYPE, int32_t>)("AUDIO_STREAM_TTS"));
1062 ASSERT_EQ((int32_t)AUDIO_STREAM_DEFAULT, (lookup<STREAM_TYPE, int32_t>)("random"));
1063
1064 ASSERT_EQ(1, (lookup<THREAD_TYPE, int32_t>)("DIRECT"));
1065 ASSERT_EQ(-1, (lookup<THREAD_TYPE, int32_t>)("random"));
1066
1067 ASSERT_EQ(getAudioTrackTraitsMap().at("static"), (lookup<TRACK_TRAITS, int32_t>)("static"));
1068 ASSERT_EQ(0, (lookup<TRACK_TRAITS, int32_t>)("random"));
1069
1070 ASSERT_EQ((int32_t)AUDIO_USAGE_VOICE_COMMUNICATION,
1071 (lookup<USAGE, int32_t>)("AUDIO_USAGE_VOICE_COMMUNICATION"));
1072 ASSERT_EQ((int32_t)AUDIO_USAGE_UNKNOWN, (lookup<USAGE, int32_t>)("random"));
1073 }
1074
1075 #if 0
1076 // Stress test code for garbage collection, you need to enable AID_SHELL as trusted to run
1077 // in MediaMetricsService.cpp.
1078 //
1079 // TODO: Make a dedicated stress test.
1080 //
1081 TEST(mediametrics_tests, gc_same_key) {
1082 // random keys ignored when empty
1083 for (int i = 0; i < 10000000; ++i) {
1084 std::unique_ptr<mediametrics::Item> test_key(mediametrics::Item::create("audio.zzz.123"));
1085 test_key->set("event#", "hello");
1086 test_key->set("value", (int)10);
1087 test_key->selfrecord();
1088 }
1089 //mediaMetrics->dump(fileno(stdout), {} /* args */);
1090 }
1091 #endif
1092
1093 // Base64Url and isLogSessionId string utilities can be tested by static asserts.
1094 static_assert(mediametrics::stringutils::isBase64Url("abc"));
1095 static_assert(mediametrics::stringutils::InverseBase64UrlTable['A'] == 0);
1096 static_assert(mediametrics::stringutils::InverseBase64UrlTable['a'] == 26);
1097 static_assert(mediametrics::stringutils::InverseBase64UrlTable['!'] ==
1098 mediametrics::stringutils::Transpose::INVALID_CHAR);
1099 static_assert(mediametrics::stringutils::InverseBase64UrlTable['@'] ==
1100 mediametrics::stringutils::Transpose::INVALID_CHAR);
1101 static_assert(mediametrics::stringutils::InverseBase64UrlTable['#'] ==
1102 mediametrics::stringutils::Transpose::INVALID_CHAR);
1103 static_assert(!mediametrics::stringutils::isBase64Url("!@#"));
1104
1105 static_assert(mediametrics::stringutils::isLogSessionId("0123456789abcdef"));
1106 static_assert(!mediametrics::stringutils::isLogSessionId("abc"));
1107 static_assert(!mediametrics::stringutils::isLogSessionId("!@#"));
1108 static_assert(!mediametrics::stringutils::isLogSessionId("0123456789abcde!"));
1109
TEST(mediametrics_tests,sanitizeLogSessionId)1110 TEST(mediametrics_tests, sanitizeLogSessionId) {
1111 // invalid id returns empty string.
1112 ASSERT_EQ("", mediametrics::stringutils::sanitizeLogSessionId("abc"));
1113
1114 // valid id passes through.
1115 std::string validId = "fedcba9876543210";
1116 ASSERT_EQ(validId, mediametrics::stringutils::sanitizeLogSessionId(validId));
1117
1118 // one more char makes the id invalid
1119 ASSERT_EQ("", mediametrics::stringutils::sanitizeLogSessionId(validId + "A"));
1120
1121 std::string validId2 = "ZYXWVUT123456789";
1122 ASSERT_EQ(validId2, mediametrics::stringutils::sanitizeLogSessionId(validId2));
1123
1124 // one fewer char makes the id invalid
1125 ASSERT_EQ("", mediametrics::stringutils::sanitizeLogSessionId(validId.c_str() + 1));
1126
1127 // replacing one character with an invalid character makes an invalid id.
1128 validId2[3] = '!';
1129 ASSERT_EQ("", mediametrics::stringutils::sanitizeLogSessionId(validId2));
1130 }
1131
TEST(mediametrics_tests,LruSet)1132 TEST(mediametrics_tests, LruSet) {
1133 constexpr size_t LRU_SET_SIZE = 2;
1134 mediametrics::LruSet<std::string> lruSet(LRU_SET_SIZE);
1135
1136 // test adding a couple strings.
1137 lruSet.add("abc");
1138 ASSERT_EQ(1u, lruSet.size());
1139 ASSERT_TRUE(lruSet.check("abc"));
1140 lruSet.add("def");
1141 ASSERT_EQ(2u, lruSet.size());
1142
1143 // now adding the third string causes eviction of the oldest.
1144 lruSet.add("ghi");
1145 ASSERT_FALSE(lruSet.check("abc"));
1146 ASSERT_TRUE(lruSet.check("ghi"));
1147 ASSERT_TRUE(lruSet.check("def")); // "def" is most recent.
1148 ASSERT_EQ(2u, lruSet.size()); // "abc" is correctly discarded.
1149
1150 // adding another string will evict the oldest.
1151 lruSet.add("foo");
1152 ASSERT_FALSE(lruSet.check("ghi")); // note: "ghi" discarded when "foo" added.
1153 ASSERT_TRUE(lruSet.check("foo"));
1154 ASSERT_TRUE(lruSet.check("def"));
1155
1156 // manual removing of a string works, too.
1157 ASSERT_TRUE(lruSet.remove("def"));
1158 ASSERT_FALSE(lruSet.check("def")); // we manually removed "def".
1159 ASSERT_TRUE(lruSet.check("foo")); // "foo" is still there.
1160 ASSERT_EQ(1u, lruSet.size());
1161
1162 // you can't remove a string that has not been added.
1163 ASSERT_FALSE(lruSet.remove("bar")); // Note: "bar" doesn't exist, so remove returns false.
1164 ASSERT_EQ(1u, lruSet.size());
1165
1166 lruSet.add("foo"); // adding "foo" (which already exists) doesn't change size.
1167 ASSERT_EQ(1u, lruSet.size());
1168 lruSet.add("bar"); // add "bar"
1169 ASSERT_EQ(2u, lruSet.size());
1170 lruSet.add("glorp"); // add "glorp" evicts "foo".
1171 ASSERT_EQ(2u, lruSet.size());
1172 ASSERT_TRUE(lruSet.check("bar"));
1173 ASSERT_TRUE(lruSet.check("glorp"));
1174 ASSERT_FALSE(lruSet.check("foo"));
1175 }
1176
TEST(mediametrics_tests,LruSet0)1177 TEST(mediametrics_tests, LruSet0) {
1178 constexpr size_t LRU_SET_SIZE = 0;
1179 mediametrics::LruSet<std::string> lruSet(LRU_SET_SIZE);
1180
1181 lruSet.add("a");
1182 ASSERT_EQ(0u, lruSet.size());
1183 ASSERT_FALSE(lruSet.check("a"));
1184 ASSERT_FALSE(lruSet.remove("a")); // never added.
1185 ASSERT_EQ(0u, lruSet.size());
1186 }
1187
1188 // Returns a 16 Base64Url string representing the decimal representation of value
1189 // (with leading 0s) e.g. 0000000000000000, 0000000000000001, 0000000000000002, ...
generateId(size_t value)1190 static std::string generateId(size_t value)
1191 {
1192 char id[16 + 1]; // to be filled with 16 Base64Url chars (and zero termination)
1193 char *sptr = id + 16; // start at the end.
1194 *sptr-- = 0; // zero terminate.
1195 // output the digits from least significant to most significant.
1196 while (value) {
1197 *sptr-- = value % 10;
1198 value /= 10;
1199 }
1200 // add leading 0's
1201 while (sptr > id) {
1202 *sptr-- = '0';
1203 }
1204 return std::string(id);
1205 }
1206
TEST(mediametrics_tests,ValidateId)1207 TEST(mediametrics_tests, ValidateId) {
1208 constexpr size_t LRU_SET_SIZE = 3;
1209 constexpr size_t IDS = 10;
1210 static_assert(IDS > LRU_SET_SIZE); // IDS must be greater than LRU_SET_SIZE.
1211 mediametrics::ValidateId validateId(LRU_SET_SIZE);
1212
1213
1214 // register IDs as integer strings counting from 0.
1215 for (size_t i = 0; i < IDS; ++i) {
1216 validateId.registerId(generateId(i));
1217 }
1218
1219 // only the last LRU_SET_SIZE exist.
1220 for (size_t i = 0; i < IDS - LRU_SET_SIZE; ++i) {
1221 ASSERT_EQ("", validateId.validateId(generateId(i)));
1222 }
1223 for (size_t i = IDS - LRU_SET_SIZE; i < IDS; ++i) {
1224 const std::string id = generateId(i);
1225 ASSERT_EQ(id, validateId.validateId(id));
1226 }
1227 }
1228
TEST(mediametrics_tests,StatusConversion)1229 TEST(mediametrics_tests, StatusConversion) {
1230 constexpr status_t statuses[] = {
1231 NO_ERROR,
1232 BAD_VALUE,
1233 DEAD_OBJECT,
1234 NO_MEMORY,
1235 PERMISSION_DENIED,
1236 INVALID_OPERATION,
1237 WOULD_BLOCK,
1238 UNKNOWN_ERROR,
1239 };
1240
1241 auto roundTrip = [](status_t status) {
1242 return android::mediametrics::statusStringToStatus(
1243 android::mediametrics::statusToStatusString(status));
1244 };
1245
1246 // Primary status error categories.
1247 for (const auto status : statuses) {
1248 ASSERT_EQ(status, roundTrip(status));
1249 }
1250
1251 // Status errors specially considered.
1252 ASSERT_EQ(DEAD_OBJECT, roundTrip(FAILED_TRANSACTION));
1253 }
1254
TEST(mediametrics_tests,HeatMap)1255 TEST(mediametrics_tests, HeatMap) {
1256 constexpr size_t SIZE = 2;
1257 android::mediametrics::HeatMap heatMap{SIZE};
1258 constexpr uid_t UID = 0;
1259 constexpr int32_t SUBCODE = 1;
1260
1261 ASSERT_EQ((size_t)0, heatMap.size());
1262 heatMap.add("someKey", "someSuffix", "someEvent",
1263 AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
1264 ASSERT_EQ((size_t)1, heatMap.size());
1265 heatMap.add("someKey", "someSuffix", "someEvent",
1266 AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
1267 heatMap.add("someKey", "someSuffix", "anotherEvent",
1268 AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT, UID, "message", SUBCODE);
1269 ASSERT_EQ((size_t)1, heatMap.size());
1270 heatMap.add("anotherKey", "someSuffix", "someEvent",
1271 AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
1272 ASSERT_EQ((size_t)2, heatMap.size());
1273 ASSERT_EQ((size_t)0, heatMap.rejected());
1274
1275 heatMap.add("thirdKey", "someSuffix", "someEvent",
1276 AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
1277 ASSERT_EQ((size_t)2, heatMap.size());
1278 ASSERT_EQ((size_t)1, heatMap.rejected());
1279
1280 android::mediametrics::HeatData heatData = heatMap.getData("someKey");
1281 ASSERT_EQ((size_t)2, heatData.size());
1282 auto count = heatData.heatCount();
1283 ASSERT_EQ((size_t)3, count.size()); // pairs in order { total, "anotherEvent", "someEvent" }
1284 // check total value
1285 ASSERT_EQ((size_t)2, count[0].first); // OK
1286 ASSERT_EQ((size_t)1, count[0].second); // ERROR;
1287 // first key "anotherEvent"
1288 ASSERT_EQ((size_t)0, count[1].first); // OK
1289 ASSERT_EQ((size_t)1, count[1].second); // ERROR;
1290 // second key "someEvent"
1291 ASSERT_EQ((size_t)2, count[2].first); // OK
1292 ASSERT_EQ((size_t)0, count[2].second); // ERROR;
1293
1294 heatMap.clear();
1295 ASSERT_EQ((size_t)0, heatMap.size());
1296 }
1297