1 // Copyright (C) 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/guardrail/StatsdStats.h"
16 #include "statslog_statsdtest.h"
17 #include "tests/statsd_test_util.h"
18 
19 #include <gtest/gtest.h>
20 #include <vector>
21 
22 #ifdef __ANDROID__
23 
24 namespace android {
25 namespace os {
26 namespace statsd {
27 
28 using std::vector;
29 
TEST(StatsdStatsTest,TestValidConfigAdd)30 TEST(StatsdStatsTest, TestValidConfigAdd) {
31     StatsdStats stats;
32     ConfigKey key(0, 12345);
33     const int metricsCount = 10;
34     const int conditionsCount = 20;
35     const int matchersCount = 30;
36     const int alertsCount = 10;
37     stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
38                              true /*valid config*/);
39     vector<uint8_t> output;
40     stats.dumpStats(&output, false /*reset stats*/);
41 
42     StatsdStatsReport report;
43     bool good = report.ParseFromArray(&output[0], output.size());
44     EXPECT_TRUE(good);
45     ASSERT_EQ(1, report.config_stats_size());
46     const auto& configReport = report.config_stats(0);
47     EXPECT_EQ(0, configReport.uid());
48     EXPECT_EQ(12345, configReport.id());
49     EXPECT_EQ(metricsCount, configReport.metric_count());
50     EXPECT_EQ(conditionsCount, configReport.condition_count());
51     EXPECT_EQ(matchersCount, configReport.matcher_count());
52     EXPECT_EQ(alertsCount, configReport.alert_count());
53     EXPECT_EQ(true, configReport.is_valid());
54     EXPECT_FALSE(configReport.has_deletion_time_sec());
55 }
56 
TEST(StatsdStatsTest,TestInvalidConfigAdd)57 TEST(StatsdStatsTest, TestInvalidConfigAdd) {
58     StatsdStats stats;
59     ConfigKey key(0, 12345);
60     const int metricsCount = 10;
61     const int conditionsCount = 20;
62     const int matchersCount = 30;
63     const int alertsCount = 10;
64     stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
65                              false /*bad config*/);
66     vector<uint8_t> output;
67     stats.dumpStats(&output, false);
68 
69     StatsdStatsReport report;
70     bool good = report.ParseFromArray(&output[0], output.size());
71     EXPECT_TRUE(good);
72     ASSERT_EQ(1, report.config_stats_size());
73     const auto& configReport = report.config_stats(0);
74     // The invalid config should be put into icebox with a deletion time.
75     EXPECT_TRUE(configReport.has_deletion_time_sec());
76 }
77 
TEST(StatsdStatsTest,TestConfigRemove)78 TEST(StatsdStatsTest, TestConfigRemove) {
79     StatsdStats stats;
80     ConfigKey key(0, 12345);
81     const int metricsCount = 10;
82     const int conditionsCount = 20;
83     const int matchersCount = 30;
84     const int alertsCount = 10;
85     stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
86                              true);
87     vector<uint8_t> output;
88     stats.dumpStats(&output, false);
89     StatsdStatsReport report;
90     bool good = report.ParseFromArray(&output[0], output.size());
91     EXPECT_TRUE(good);
92     ASSERT_EQ(1, report.config_stats_size());
93     const auto& configReport = report.config_stats(0);
94     EXPECT_FALSE(configReport.has_deletion_time_sec());
95 
96     stats.noteConfigRemoved(key);
97     stats.dumpStats(&output, false);
98     good = report.ParseFromArray(&output[0], output.size());
99     EXPECT_TRUE(good);
100     ASSERT_EQ(1, report.config_stats_size());
101     const auto& configReport2 = report.config_stats(0);
102     EXPECT_TRUE(configReport2.has_deletion_time_sec());
103 }
104 
TEST(StatsdStatsTest,TestSubStats)105 TEST(StatsdStatsTest, TestSubStats) {
106     StatsdStats stats;
107     ConfigKey key(0, 12345);
108     stats.noteConfigReceived(key, 2, 3, 4, 5, {std::make_pair(123, 456)}, true);
109 
110     stats.noteMatcherMatched(key, StringToId("matcher1"));
111     stats.noteMatcherMatched(key, StringToId("matcher1"));
112     stats.noteMatcherMatched(key, StringToId("matcher2"));
113 
114     stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
115     stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
116 
117     stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
118     stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
119 
120     stats.noteAnomalyDeclared(key, StringToId("alert1"));
121     stats.noteAnomalyDeclared(key, StringToId("alert1"));
122     stats.noteAnomalyDeclared(key, StringToId("alert2"));
123 
124     // broadcast-> 2
125     stats.noteBroadcastSent(key);
126     stats.noteBroadcastSent(key);
127 
128     // data drop -> 1
129     stats.noteDataDropped(key, 123);
130 
131     // dump report -> 3
132     stats.noteMetricsReportSent(key, 0);
133     stats.noteMetricsReportSent(key, 0);
134     stats.noteMetricsReportSent(key, 0);
135 
136     // activation_time_sec -> 2
137     stats.noteActiveStatusChanged(key, true);
138     stats.noteActiveStatusChanged(key, true);
139 
140     // deactivation_time_sec -> 1
141     stats.noteActiveStatusChanged(key, false);
142 
143     vector<uint8_t> output;
144     stats.dumpStats(&output, true);  // Dump and reset stats
145     StatsdStatsReport report;
146     bool good = report.ParseFromArray(&output[0], output.size());
147     EXPECT_TRUE(good);
148     ASSERT_EQ(1, report.config_stats_size());
149     const auto& configReport = report.config_stats(0);
150     ASSERT_EQ(2, configReport.broadcast_sent_time_sec_size());
151     ASSERT_EQ(1, configReport.data_drop_time_sec_size());
152     ASSERT_EQ(1, configReport.data_drop_bytes_size());
153     EXPECT_EQ(123, configReport.data_drop_bytes(0));
154     ASSERT_EQ(3, configReport.dump_report_time_sec_size());
155     ASSERT_EQ(3, configReport.dump_report_data_size_size());
156     ASSERT_EQ(2, configReport.activation_time_sec_size());
157     ASSERT_EQ(1, configReport.deactivation_time_sec_size());
158     ASSERT_EQ(1, configReport.annotation_size());
159     EXPECT_EQ(123, configReport.annotation(0).field_int64());
160     EXPECT_EQ(456, configReport.annotation(0).field_int32());
161 
162     ASSERT_EQ(2, configReport.matcher_stats_size());
163     // matcher1 is the first in the list
164     if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
165         EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
166         EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
167         EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
168     } else {
169         // matcher1 is the second in the list.
170         EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
171         EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
172 
173         EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
174         EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
175     }
176 
177     ASSERT_EQ(2, configReport.alert_stats_size());
178     bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
179     EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
180     EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
181     EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
182     EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
183 
184     ASSERT_EQ(1, configReport.condition_stats_size());
185     EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
186     EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
187 
188     ASSERT_EQ(1, configReport.metric_stats_size());
189     EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
190     EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
191 
192     // after resetting the stats, some new events come
193     stats.noteMatcherMatched(key, StringToId("matcher99"));
194     stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
195     stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
196     stats.noteAnomalyDeclared(key, StringToId("alert99"));
197 
198     // now the config stats should only contain the stats about the new event.
199     stats.dumpStats(&output, false);
200     good = report.ParseFromArray(&output[0], output.size());
201     EXPECT_TRUE(good);
202     ASSERT_EQ(1, report.config_stats_size());
203     const auto& configReport2 = report.config_stats(0);
204     ASSERT_EQ(1, configReport2.matcher_stats_size());
205     EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
206     EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
207 
208     ASSERT_EQ(1, configReport2.condition_stats_size());
209     EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
210     EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
211 
212     ASSERT_EQ(1, configReport2.metric_stats_size());
213     EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
214     EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
215 
216     ASSERT_EQ(1, configReport2.alert_stats_size());
217     EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
218     EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
219 }
220 
TEST(StatsdStatsTest,TestAtomLog)221 TEST(StatsdStatsTest, TestAtomLog) {
222     StatsdStats stats;
223     time_t now = time(nullptr);
224     // old event, we get it from the stats buffer. should be ignored.
225     stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, 1000);
226 
227     stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 1);
228     stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 2);
229     stats.noteAtomLogged(util::APP_CRASH_OCCURRED, now + 3);
230 
231     vector<uint8_t> output;
232     stats.dumpStats(&output, false);
233     StatsdStatsReport report;
234     bool good = report.ParseFromArray(&output[0], output.size());
235     EXPECT_TRUE(good);
236 
237     ASSERT_EQ(2, report.atom_stats_size());
238     bool sensorAtomGood = false;
239     bool dropboxAtomGood = false;
240 
241     for (const auto& atomStats : report.atom_stats()) {
242         if (atomStats.tag() == util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
243             sensorAtomGood = true;
244         }
245         if (atomStats.tag() == util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
246             dropboxAtomGood = true;
247         }
248     }
249 
250     EXPECT_TRUE(dropboxAtomGood);
251     EXPECT_TRUE(sensorAtomGood);
252 }
253 
TEST(StatsdStatsTest,TestNonPlatformAtomLog)254 TEST(StatsdStatsTest, TestNonPlatformAtomLog) {
255     StatsdStats stats;
256     time_t now = time(nullptr);
257     int newAtom1 = StatsdStats::kMaxPushedAtomId + 1;
258     int newAtom2 = StatsdStats::kMaxPushedAtomId + 2;
259 
260     stats.noteAtomLogged(newAtom1, now + 1);
261     stats.noteAtomLogged(newAtom1, now + 2);
262     stats.noteAtomLogged(newAtom2, now + 3);
263 
264     vector<uint8_t> output;
265     stats.dumpStats(&output, false);
266     StatsdStatsReport report;
267     bool good = report.ParseFromArray(&output[0], output.size());
268     EXPECT_TRUE(good);
269 
270     ASSERT_EQ(2, report.atom_stats_size());
271     bool newAtom1Good = false;
272     bool newAtom2Good = false;
273 
274     for (const auto& atomStats : report.atom_stats()) {
275         if (atomStats.tag() == newAtom1 && atomStats.count() == 2) {
276             newAtom1Good = true;
277         }
278         if (atomStats.tag() == newAtom2 && atomStats.count() == 1) {
279             newAtom2Good = true;
280         }
281     }
282 
283     EXPECT_TRUE(newAtom1Good);
284     EXPECT_TRUE(newAtom2Good);
285 }
286 
TEST(StatsdStatsTest,TestPullAtomStats)287 TEST(StatsdStatsTest, TestPullAtomStats) {
288     StatsdStats stats;
289 
290     stats.updateMinPullIntervalSec(util::DISK_SPACE, 3333L);
291     stats.updateMinPullIntervalSec(util::DISK_SPACE, 2222L);
292     stats.updateMinPullIntervalSec(util::DISK_SPACE, 4444L);
293 
294     stats.notePull(util::DISK_SPACE);
295     stats.notePullTime(util::DISK_SPACE, 1111L);
296     stats.notePullDelay(util::DISK_SPACE, 1111L);
297     stats.notePull(util::DISK_SPACE);
298     stats.notePullTime(util::DISK_SPACE, 3333L);
299     stats.notePullDelay(util::DISK_SPACE, 3335L);
300     stats.notePull(util::DISK_SPACE);
301     stats.notePullFromCache(util::DISK_SPACE);
302     stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
303     stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, false);
304     stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
305     stats.notePullBinderCallFailed(util::DISK_SPACE);
306     stats.notePullUidProviderNotFound(util::DISK_SPACE);
307     stats.notePullerNotFound(util::DISK_SPACE);
308     stats.notePullerNotFound(util::DISK_SPACE);
309     stats.notePullTimeout(util::DISK_SPACE, 3000L, 6000L);
310     stats.notePullTimeout(util::DISK_SPACE, 4000L, 7000L);
311 
312     vector<uint8_t> output;
313     stats.dumpStats(&output, false);
314     StatsdStatsReport report;
315     bool good = report.ParseFromArray(&output[0], output.size());
316     EXPECT_TRUE(good);
317 
318     ASSERT_EQ(1, report.pulled_atom_stats_size());
319 
320     EXPECT_EQ(util::DISK_SPACE, report.pulled_atom_stats(0).atom_id());
321     EXPECT_EQ(3, report.pulled_atom_stats(0).total_pull());
322     EXPECT_EQ(1, report.pulled_atom_stats(0).total_pull_from_cache());
323     EXPECT_EQ(2222L, report.pulled_atom_stats(0).min_pull_interval_sec());
324     EXPECT_EQ(2222L, report.pulled_atom_stats(0).average_pull_time_nanos());
325     EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos());
326     EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos());
327     EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
328     EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
329     EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
330     EXPECT_EQ(1L, report.pulled_atom_stats(0).binder_call_failed());
331     EXPECT_EQ(1L, report.pulled_atom_stats(0).failed_uid_provider_not_found());
332     EXPECT_EQ(2L, report.pulled_atom_stats(0).puller_not_found());
333     ASSERT_EQ(2, report.pulled_atom_stats(0).pull_atom_metadata_size());
334     EXPECT_EQ(3000L, report.pulled_atom_stats(0).pull_atom_metadata(0).pull_timeout_uptime_millis());
335     EXPECT_EQ(4000L, report.pulled_atom_stats(0).pull_atom_metadata(1).pull_timeout_uptime_millis());
336     EXPECT_EQ(6000L, report.pulled_atom_stats(0).pull_atom_metadata(0)
337             .pull_timeout_elapsed_millis());
338     EXPECT_EQ(7000L, report.pulled_atom_stats(0).pull_atom_metadata(1)
339             .pull_timeout_elapsed_millis());
340 }
341 
TEST(StatsdStatsTest,TestAtomMetricsStats)342 TEST(StatsdStatsTest, TestAtomMetricsStats) {
343     StatsdStats stats;
344     time_t now = time(nullptr);
345     // old event, we get it from the stats buffer. should be ignored.
346     stats.noteBucketDropped(1000L);
347 
348     stats.noteBucketBoundaryDelayNs(1000L, -1L);
349     stats.noteBucketBoundaryDelayNs(1000L, -10L);
350     stats.noteBucketBoundaryDelayNs(1000L, 2L);
351 
352     stats.noteBucketBoundaryDelayNs(1001L, 1L);
353 
354     vector<uint8_t> output;
355     stats.dumpStats(&output, false);
356     StatsdStatsReport report;
357     bool good = report.ParseFromArray(&output[0], output.size());
358     EXPECT_TRUE(good);
359 
360     ASSERT_EQ(2, report.atom_metric_stats().size());
361 
362     auto atomStats = report.atom_metric_stats(0);
363     EXPECT_EQ(1000L, atomStats.metric_id());
364     EXPECT_EQ(1L, atomStats.bucket_dropped());
365     EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns());
366     EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns());
367 
368     auto atomStats2 = report.atom_metric_stats(1);
369     EXPECT_EQ(1001L, atomStats2.metric_id());
370     EXPECT_EQ(0L, atomStats2.bucket_dropped());
371     EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns());
372     EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns());
373 }
374 
TEST(StatsdStatsTest,TestAnomalyMonitor)375 TEST(StatsdStatsTest, TestAnomalyMonitor) {
376     StatsdStats stats;
377     stats.noteRegisteredAnomalyAlarmChanged();
378     stats.noteRegisteredAnomalyAlarmChanged();
379 
380     vector<uint8_t> output;
381     stats.dumpStats(&output, false);
382     StatsdStatsReport report;
383     bool good = report.ParseFromArray(&output[0], output.size());
384     EXPECT_TRUE(good);
385 
386     EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
387 }
388 
TEST(StatsdStatsTest,TestTimestampThreshold)389 TEST(StatsdStatsTest, TestTimestampThreshold) {
390     StatsdStats stats;
391     vector<int32_t> timestamps;
392     for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
393         timestamps.push_back(i);
394     }
395     ConfigKey key(0, 12345);
396     stats.noteConfigReceived(key, 2, 3, 4, 5, {}, true);
397 
398     for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
399         stats.noteDataDropped(key, timestamps[i]);
400         stats.noteBroadcastSent(key, timestamps[i]);
401         stats.noteMetricsReportSent(key, 0, timestamps[i]);
402         stats.noteActiveStatusChanged(key, true, timestamps[i]);
403         stats.noteActiveStatusChanged(key, false, timestamps[i]);
404     }
405 
406     int32_t newTimestamp = 10000;
407 
408     // now it should trigger removing oldest timestamp
409     stats.noteDataDropped(key, 123, 10000);
410     stats.noteBroadcastSent(key, 10000);
411     stats.noteMetricsReportSent(key, 0, 10000);
412     stats.noteActiveStatusChanged(key, true, 10000);
413     stats.noteActiveStatusChanged(key, false, 10000);
414 
415     EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
416     const auto& configStats = stats.mConfigStats[key];
417 
418     size_t maxCount = StatsdStats::kMaxTimestampCount;
419     ASSERT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
420     ASSERT_EQ(maxCount, configStats->data_drop_time_sec.size());
421     ASSERT_EQ(maxCount, configStats->dump_report_stats.size());
422     ASSERT_EQ(maxCount, configStats->activation_time_sec.size());
423     ASSERT_EQ(maxCount, configStats->deactivation_time_sec.size());
424 
425     // the oldest timestamp is the second timestamp in history
426     EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
427     EXPECT_EQ(1, configStats->data_drop_bytes.front());
428     EXPECT_EQ(1, configStats->dump_report_stats.front().first);
429     EXPECT_EQ(1, configStats->activation_time_sec.front());
430     EXPECT_EQ(1, configStats->deactivation_time_sec.front());
431 
432     // the last timestamp is the newest timestamp.
433     EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
434     EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
435     EXPECT_EQ(123, configStats->data_drop_bytes.back());
436     EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
437     EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
438     EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
439 }
440 
TEST(StatsdStatsTest,TestSystemServerCrash)441 TEST(StatsdStatsTest, TestSystemServerCrash) {
442     StatsdStats stats;
443     vector<int32_t> timestamps;
444     for (int i = 0; i < StatsdStats::kMaxSystemServerRestarts; i++) {
445         timestamps.push_back(i);
446         stats.noteSystemServerRestart(timestamps[i]);
447     }
448     vector<uint8_t> output;
449     stats.dumpStats(&output, false);
450     StatsdStatsReport report;
451     EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
452     const int maxCount = StatsdStats::kMaxSystemServerRestarts;
453     ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
454 
455     stats.noteSystemServerRestart(StatsdStats::kMaxSystemServerRestarts + 1);
456     output.clear();
457     stats.dumpStats(&output, false);
458     EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
459     ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
460     EXPECT_EQ(StatsdStats::kMaxSystemServerRestarts + 1, report.system_restart_sec(maxCount - 1));
461 }
462 
TEST(StatsdStatsTest,TestActivationBroadcastGuardrailHit)463 TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit) {
464     StatsdStats stats;
465     int uid1 = 1;
466     int uid2 = 2;
467     stats.noteActivationBroadcastGuardrailHit(uid1, 10);
468     stats.noteActivationBroadcastGuardrailHit(uid1, 20);
469 
470     // Test that we only keep 20 timestamps.
471     for (int i = 0; i < 100; i++) {
472         stats.noteActivationBroadcastGuardrailHit(uid2, i);
473     }
474 
475     vector<uint8_t> output;
476     stats.dumpStats(&output, false);
477     StatsdStatsReport report;
478     EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
479 
480     ASSERT_EQ(2, report.activation_guardrail_stats_size());
481     bool uid1Good = false;
482     bool uid2Good = false;
483     for (const auto& guardrailTimes : report.activation_guardrail_stats()) {
484         if (uid1 == guardrailTimes.uid()) {
485             uid1Good = true;
486             ASSERT_EQ(2, guardrailTimes.guardrail_met_sec_size());
487             EXPECT_EQ(10, guardrailTimes.guardrail_met_sec(0));
488             EXPECT_EQ(20, guardrailTimes.guardrail_met_sec(1));
489         } else if (uid2 == guardrailTimes.uid()) {
490             int maxCount = StatsdStats::kMaxTimestampCount;
491             uid2Good = true;
492             ASSERT_EQ(maxCount, guardrailTimes.guardrail_met_sec_size());
493             for (int i = 0; i < maxCount; i++) {
494                 EXPECT_EQ(100 - maxCount + i, guardrailTimes.guardrail_met_sec(i));
495             }
496         } else {
497             FAIL() << "Unexpected uid.";
498         }
499     }
500     EXPECT_TRUE(uid1Good);
501     EXPECT_TRUE(uid2Good);
502 }
503 
TEST(StatsdStatsTest,TestAtomErrorStats)504 TEST(StatsdStatsTest, TestAtomErrorStats) {
505     StatsdStats stats;
506 
507     int pushAtomTag = 100;
508     int pullAtomTag = 1000;
509     int numErrors = 10;
510 
511     for (int i = 0; i < numErrors; i++) {
512         // We must call noteAtomLogged as well because only those pushed atoms
513         // that have been logged will have stats printed about them in the
514         // proto.
515         stats.noteAtomLogged(pushAtomTag, /*timeSec=*/0);
516         stats.noteAtomError(pushAtomTag, /*pull=*/false);
517 
518         stats.noteAtomError(pullAtomTag, /*pull=*/true);
519     }
520 
521     vector<uint8_t> output;
522     stats.dumpStats(&output, false);
523     StatsdStatsReport report;
524     EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
525 
526     // Check error count = numErrors for push atom
527     ASSERT_EQ(1, report.atom_stats_size());
528     const auto& pushedAtomStats = report.atom_stats(0);
529     EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
530     EXPECT_EQ(numErrors, pushedAtomStats.error_count());
531 
532     // Check error count = numErrors for pull atom
533     ASSERT_EQ(1, report.pulled_atom_stats_size());
534     const auto& pulledAtomStats = report.pulled_atom_stats(0);
535     EXPECT_EQ(pullAtomTag, pulledAtomStats.atom_id());
536     EXPECT_EQ(numErrors, pulledAtomStats.atom_error_count());
537 }
538 
539 }  // namespace statsd
540 }  // namespace os
541 }  // namespace android
542 #else
543 GTEST_LOG_(INFO) << "This test does nothing.\n";
544 #endif
545