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