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 <gtest/gtest.h>
16 
17 #include <vector>
18 
19 #include "src/StatsLogProcessor.h"
20 #include "src/stats_log_util.h"
21 #include "stats_event.h"
22 #include "tests/statsd_test_util.h"
23 
24 namespace android {
25 namespace os {
26 namespace statsd {
27 
28 #ifdef __ANDROID__
29 
30 namespace {
31 
CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type)32 StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type) {
33     StatsdConfig config;
34     *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
35     *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
36 
37     auto atomMatcher = CreateSimpleAtomMatcher("", util::APP_START_OCCURRED);
38     *config.add_atom_matcher() = atomMatcher;
39 
40     auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
41     *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
42         CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
43     *config.add_predicate() = isInBackgroundPredicate;
44 
45     auto gaugeMetric = config.add_gauge_metric();
46     gaugeMetric->set_id(123456);
47     gaugeMetric->set_what(atomMatcher.id());
48     gaugeMetric->set_condition(isInBackgroundPredicate.id());
49     gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
50     gaugeMetric->set_sampling_type(sampling_type);
51     auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
52     fieldMatcher->set_field(util::APP_START_OCCURRED);
53     fieldMatcher->add_child()->set_field(3);  // type (enum)
54     fieldMatcher->add_child()->set_field(4);  // activity_name(str)
55     fieldMatcher->add_child()->set_field(7);  // activity_start_msec(int64)
56     *gaugeMetric->mutable_dimensions_in_what() =
57         CreateDimensions(util::APP_START_OCCURRED, {1 /* uid field */ });
58     gaugeMetric->set_bucket(FIVE_MINUTES);
59 
60     auto links = gaugeMetric->add_links();
61     links->set_condition(isInBackgroundPredicate.id());
62     auto dimensionWhat = links->mutable_fields_in_what();
63     dimensionWhat->set_field(util::APP_START_OCCURRED);
64     dimensionWhat->add_child()->set_field(1);  // uid field.
65     auto dimensionCondition = links->mutable_fields_in_condition();
66     dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
67     dimensionCondition->add_child()->set_field(1);  // uid field.
68     return config;
69 }
70 
CreateStatsdConfigForRepeatedFieldsPushedEvent(const GaugeMetric::SamplingType sampling_type)71 StatsdConfig CreateStatsdConfigForRepeatedFieldsPushedEvent(
72         const GaugeMetric::SamplingType sampling_type) {
73     StatsdConfig config;
74 
75     AtomMatcher testAtomReportedAtomMatcher =
76             CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
77     *config.add_atom_matcher() = testAtomReportedAtomMatcher;
78 
79     GaugeMetric* gaugeMetric = config.add_gauge_metric();
80     gaugeMetric->set_id(123456);
81     gaugeMetric->set_what(testAtomReportedAtomMatcher.id());
82     gaugeMetric->set_sampling_type(sampling_type);
83     FieldMatcher* fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
84     fieldMatcher->set_field(util::TEST_ATOM_REPORTED);
85 
86     FieldMatcher* childFieldMatcher = fieldMatcher->add_child();
87     childFieldMatcher->set_field(9);  // repeated_int_field
88     childFieldMatcher->set_position(Position::FIRST);
89 
90     childFieldMatcher = fieldMatcher->add_child();
91     childFieldMatcher->set_field(10);  // repeated_long_field
92     childFieldMatcher->set_position(Position::LAST);
93 
94     childFieldMatcher = fieldMatcher->add_child();
95     childFieldMatcher->set_field(11);  // repeated_float_field
96     childFieldMatcher->set_position(Position::ALL);
97 
98     childFieldMatcher = fieldMatcher->add_child();
99     childFieldMatcher->set_field(12);  // repeated_string_field
100     childFieldMatcher->set_position(Position::FIRST);
101 
102     childFieldMatcher = fieldMatcher->add_child();
103     childFieldMatcher->set_field(13);  // repeated_boolean_field
104     childFieldMatcher->set_position(Position::LAST);
105 
106     childFieldMatcher = fieldMatcher->add_child();
107     childFieldMatcher->set_field(14);  // repeated_enum_field
108     childFieldMatcher->set_position(Position::ALL);
109 
110     gaugeMetric->set_bucket(FIVE_MINUTES);
111     return config;
112 }
113 
114 }  // namespace
115 
116 // Setup for test fixture.
117 class GaugeMetricE2ePushedTest : public ::testing::Test {
SetUp()118     void SetUp() override {
119         FlagProvider::getInstance().overrideFuncs(&isAtLeastSFuncTrue);
120     }
121 
TearDown()122     void TearDown() override {
123         FlagProvider::getInstance().resetOverrides();
124     }
125 
126 public:
127     void doTestRepeatedFieldsForPushedEvent();
128 };
129 
TEST_F(GaugeMetricE2ePushedTest,TestMultipleFieldsForPushedEvent)130 TEST_F(GaugeMetricE2ePushedTest, TestMultipleFieldsForPushedEvent) {
131     for (const auto& sampling_type :
132          {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
133         auto config = CreateStatsdConfigForPushedEvent(sampling_type);
134         int64_t bucketStartTimeNs = 10000000000;
135         int64_t bucketSizeNs =
136                 TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
137 
138         ConfigKey cfgKey;
139         auto processor =
140                 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
141         ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
142         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
143 
144         int appUid1 = 123;
145         int appUid2 = 456;
146         std::vector<std::unique_ptr<LogEvent>> events;
147         events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1));
148         events.push_back(
149                 CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1));
150         events.push_back(
151                 CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1));
152         events.push_back(
153                 CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1));
154 
155         events.push_back(CreateAppStartOccurredEvent(
156                 bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1",
157                 "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/));
158         events.push_back(CreateAppStartOccurredEvent(
159                 bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2",
160                 "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/));
161         events.push_back(CreateAppStartOccurredEvent(
162                 bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3",
163                 "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/));
164         events.push_back(CreateAppStartOccurredEvent(
165                 bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM,
166                 "activity_name4", "calling_pkg_name4", true /*is_instant_app*/,
167                 104 /*activity_start_msec*/));
168         events.push_back(CreateAppStartOccurredEvent(
169                 bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD,
170                 "activity_name5", "calling_pkg_name5", true /*is_instant_app*/,
171                 105 /*activity_start_msec*/));
172         events.push_back(CreateAppStartOccurredEvent(
173                 bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT,
174                 "activity_name6", "calling_pkg_name6", false /*is_instant_app*/,
175                 106 /*activity_start_msec*/));
176 
177         events.push_back(
178                 CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2));
179         events.push_back(CreateAppStartOccurredEvent(
180                 bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD,
181                 "activity_name7", "calling_pkg_name7", true /*is_instant_app*/,
182                 201 /*activity_start_msec*/));
183 
184         sortLogEventsByTimestamp(&events);
185 
186         for (const auto& event : events) {
187             processor->OnLogEvent(event.get());
188         }
189         ConfigMetricsReportList reports;
190         vector<uint8_t> buffer;
191         processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
192                                 FAST, &buffer);
193         EXPECT_TRUE(buffer.size() > 0);
194         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
195         backfillDimensionPath(&reports);
196         backfillStringInReport(&reports);
197         backfillStartEndTimestamp(&reports);
198         backfillAggregatedAtoms(&reports);
199         ASSERT_EQ(1, reports.reports_size());
200         ASSERT_EQ(1, reports.reports(0).metrics_size());
201         EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
202         StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
203         sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
204                                         &gaugeMetrics);
205         ASSERT_EQ(2, gaugeMetrics.data_size());
206 
207         auto data = gaugeMetrics.data(0);
208         EXPECT_EQ(util::APP_START_OCCURRED, data.dimensions_in_what().field());
209         ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
210         EXPECT_EQ(1 /* uid field */,
211                   data.dimensions_in_what().value_tuple().dimensions_value(0).field());
212         EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
213         ASSERT_EQ(3, data.bucket_info_size());
214         if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
215             ASSERT_EQ(2, data.bucket_info(0).atom_size());
216             ASSERT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
217             ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
218             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
219             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
220                       data.bucket_info(0).end_bucket_elapsed_nanos());
221             EXPECT_EQ(AppStartOccurred::HOT,
222                       data.bucket_info(0).atom(0).app_start_occurred().type());
223             EXPECT_EQ("activity_name2",
224                       data.bucket_info(0).atom(0).app_start_occurred().activity_name());
225             EXPECT_EQ(102L,
226                       data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
227             EXPECT_EQ(AppStartOccurred::COLD,
228                       data.bucket_info(0).atom(1).app_start_occurred().type());
229             EXPECT_EQ("activity_name3",
230                       data.bucket_info(0).atom(1).app_start_occurred().activity_name());
231             EXPECT_EQ(103L,
232                       data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
233 
234             ASSERT_EQ(1, data.bucket_info(1).atom_size());
235             ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
236             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
237                       data.bucket_info(1).start_bucket_elapsed_nanos());
238             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
239                       data.bucket_info(1).end_bucket_elapsed_nanos());
240             EXPECT_EQ(AppStartOccurred::WARM,
241                       data.bucket_info(1).atom(0).app_start_occurred().type());
242             EXPECT_EQ("activity_name4",
243                       data.bucket_info(1).atom(0).app_start_occurred().activity_name());
244             EXPECT_EQ(104L,
245                       data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
246 
247             ASSERT_EQ(2, data.bucket_info(2).atom_size());
248             ASSERT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
249             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
250                       data.bucket_info(2).start_bucket_elapsed_nanos());
251             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
252                       data.bucket_info(2).end_bucket_elapsed_nanos());
253             EXPECT_EQ(AppStartOccurred::COLD,
254                       data.bucket_info(2).atom(0).app_start_occurred().type());
255             EXPECT_EQ("activity_name5",
256                       data.bucket_info(2).atom(0).app_start_occurred().activity_name());
257             EXPECT_EQ(105L,
258                       data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
259             EXPECT_EQ(AppStartOccurred::HOT,
260                       data.bucket_info(2).atom(1).app_start_occurred().type());
261             EXPECT_EQ("activity_name6",
262                       data.bucket_info(2).atom(1).app_start_occurred().activity_name());
263             EXPECT_EQ(106L,
264                       data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
265         } else {
266             ASSERT_EQ(1, data.bucket_info(0).atom_size());
267             ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
268             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
269             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
270                       data.bucket_info(0).end_bucket_elapsed_nanos());
271             EXPECT_EQ(AppStartOccurred::HOT,
272                       data.bucket_info(0).atom(0).app_start_occurred().type());
273             EXPECT_EQ("activity_name2",
274                       data.bucket_info(0).atom(0).app_start_occurred().activity_name());
275             EXPECT_EQ(102L,
276                       data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
277 
278             ASSERT_EQ(1, data.bucket_info(1).atom_size());
279             ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
280             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
281                       data.bucket_info(1).start_bucket_elapsed_nanos());
282             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
283                       data.bucket_info(1).end_bucket_elapsed_nanos());
284             EXPECT_EQ(AppStartOccurred::WARM,
285                       data.bucket_info(1).atom(0).app_start_occurred().type());
286             EXPECT_EQ("activity_name4",
287                       data.bucket_info(1).atom(0).app_start_occurred().activity_name());
288             EXPECT_EQ(104L,
289                       data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
290 
291             ASSERT_EQ(1, data.bucket_info(2).atom_size());
292             ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
293             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
294                       data.bucket_info(2).start_bucket_elapsed_nanos());
295             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
296                       data.bucket_info(2).end_bucket_elapsed_nanos());
297             EXPECT_EQ(AppStartOccurred::COLD,
298                       data.bucket_info(2).atom(0).app_start_occurred().type());
299             EXPECT_EQ("activity_name5",
300                       data.bucket_info(2).atom(0).app_start_occurred().activity_name());
301             EXPECT_EQ(105L,
302                       data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
303         }
304 
305         data = gaugeMetrics.data(1);
306 
307         EXPECT_EQ(data.dimensions_in_what().field(), util::APP_START_OCCURRED);
308         ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
309         EXPECT_EQ(1 /* uid field */,
310                   data.dimensions_in_what().value_tuple().dimensions_value(0).field());
311         EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
312         ASSERT_EQ(1, data.bucket_info_size());
313         ASSERT_EQ(1, data.bucket_info(0).atom_size());
314         ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
315         EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
316                   data.bucket_info(0).start_bucket_elapsed_nanos());
317         EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
318                   data.bucket_info(0).end_bucket_elapsed_nanos());
319         EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
320         EXPECT_EQ("activity_name7",
321                   data.bucket_info(0).atom(0).app_start_occurred().activity_name());
322         EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
323     }
324 }
325 
TEST_F_GUARDED(GaugeMetricE2ePushedTest,TestRepeatedFieldsForPushedEvent,__ANDROID_API_T__)326 TEST_F_GUARDED(GaugeMetricE2ePushedTest, TestRepeatedFieldsForPushedEvent, __ANDROID_API_T__) {
327     for (const auto& sampling_type :
328          {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
329         StatsdConfig config = CreateStatsdConfigForRepeatedFieldsPushedEvent(sampling_type);
330         int64_t bucketStartTimeNs = 10000000000;
331         int64_t bucketSizeNs =
332                 TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
333 
334         ConfigKey cfgKey;
335         sp<StatsLogProcessor> processor =
336                 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
337 
338         std::vector<std::unique_ptr<LogEvent>> events;
339 
340         vector<int> intArray = {3, 6};
341         vector<int64_t> longArray = {1000L, 10002L};
342         vector<float> floatArray = {0.3f, 0.09f};
343         vector<string> stringArray = {"str1", "str2"};
344         int boolArrayLength = 2;
345         bool boolArray[boolArrayLength];
346         boolArray[0] = 1;
347         boolArray[1] = 0;
348         vector<uint8_t> boolArrayVector = {1, 0};
349         vector<int> enumArray = {TestAtomReported::ON, TestAtomReported::OFF};
350 
351         events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
352                 bucketStartTimeNs + 10 * NS_PER_SEC, intArray, longArray, floatArray, stringArray,
353                 boolArray, boolArrayLength, enumArray));
354         events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
355                 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {}));
356 
357         for (const auto& event : events) {
358             processor->OnLogEvent(event.get());
359         }
360 
361         ConfigMetricsReportList reports;
362         vector<uint8_t> buffer;
363         processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
364                                 FAST, &buffer);
365         EXPECT_TRUE(buffer.size() > 0);
366         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
367         backfillDimensionPath(&reports);
368         backfillStringInReport(&reports);
369         backfillStartEndTimestamp(&reports);
370         backfillAggregatedAtoms(&reports);
371 
372         ASSERT_EQ(1, reports.reports_size());
373         ASSERT_EQ(1, reports.reports(0).metrics_size());
374         StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
375         sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
376                                         &gaugeMetrics);
377         ASSERT_EQ(1, gaugeMetrics.data_size());
378 
379         GaugeMetricData data = gaugeMetrics.data(0);
380         ASSERT_EQ(1, data.bucket_info_size());
381         if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
382             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
383             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
384                       data.bucket_info(0).end_bucket_elapsed_nanos());
385             ASSERT_EQ(2, data.bucket_info(0).atom_size());
386 
387             TestAtomReported atom = data.bucket_info(0).atom(0).test_atom_reported();
388             EXPECT_THAT(atom.repeated_int_field(), ElementsAreArray({3}));
389             EXPECT_THAT(atom.repeated_long_field(), ElementsAreArray({10002L}));
390             EXPECT_THAT(atom.repeated_float_field(), ElementsAreArray(floatArray));
391             EXPECT_THAT(atom.repeated_string_field(), ElementsAreArray({"str1"}));
392             EXPECT_THAT(atom.repeated_boolean_field(), ElementsAreArray({0}));
393             EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArray));
394 
395             atom = data.bucket_info(0).atom(1).test_atom_reported();
396             EXPECT_EQ(atom.repeated_int_field_size(), 0);
397             EXPECT_EQ(atom.repeated_long_field_size(), 0);
398             EXPECT_EQ(atom.repeated_float_field_size(), 0);
399             EXPECT_EQ(atom.repeated_string_field_size(), 0);
400             EXPECT_EQ(atom.repeated_boolean_field_size(), 0);
401             EXPECT_EQ(atom.repeated_enum_field_size(), 0);
402         } else {
403             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
404             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
405                       data.bucket_info(0).end_bucket_elapsed_nanos());
406             ASSERT_EQ(1, data.bucket_info(0).atom_size());
407 
408             TestAtomReported atom = data.bucket_info(0).atom(0).test_atom_reported();
409             EXPECT_THAT(atom.repeated_int_field(), ElementsAreArray({3}));
410             EXPECT_THAT(atom.repeated_long_field(), ElementsAreArray({10002L}));
411             EXPECT_THAT(atom.repeated_float_field(), ElementsAreArray(floatArray));
412             EXPECT_THAT(atom.repeated_string_field(), ElementsAreArray({"str1"}));
413             EXPECT_THAT(atom.repeated_boolean_field(), ElementsAreArray({0}));
414             EXPECT_THAT(atom.repeated_enum_field(), ElementsAreArray(enumArray));
415         }
416     }
417 }
418 
TEST_F(GaugeMetricE2ePushedTest,TestDimensionalSampling)419 TEST_F(GaugeMetricE2ePushedTest, TestDimensionalSampling) {
420     ShardOffsetProvider::getInstance().setShardOffset(5);
421 
422     StatsdConfig config;
423 
424     AtomMatcher appCrashMatcher =
425             CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
426     *config.add_atom_matcher() = appCrashMatcher;
427 
428     GaugeMetric sampledGaugeMetric =
429             createGaugeMetric("GaugeSampledAppCrashesPerUid", appCrashMatcher.id(),
430                               GaugeMetric::FIRST_N_SAMPLES, nullopt, nullopt);
431     *sampledGaugeMetric.mutable_dimensions_in_what() =
432             CreateDimensions(util::APP_CRASH_OCCURRED, {1 /* uid */});
433     *sampledGaugeMetric.mutable_dimensional_sampling_info()->mutable_sampled_what_field() =
434             CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
435     sampledGaugeMetric.mutable_dimensional_sampling_info()->set_shard_count(2);
436     *config.add_gauge_metric() = sampledGaugeMetric;
437 
438     const int64_t configAddedTimeNs = 10 * NS_PER_SEC;  // 0:10
439     const int64_t bucketSizeNs =
440             TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000LL * 1000LL;
441 
442     int uid = 12345;
443     int64_t cfgId = 98765;
444     ConfigKey cfgKey(uid, cfgId);
445 
446     sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
447             configAddedTimeNs, configAddedTimeNs, config, cfgKey, nullptr, 0, new UidMap());
448 
449     int appUid1 = 1001;  // odd hash value
450     int appUid2 = 1002;  // even hash value
451     int appUid3 = 1003;  // odd hash value
452 
453     const int64_t gaugeEventTimeNs1 = configAddedTimeNs + 20 * NS_PER_SEC;
454     const int64_t gaugeEventTimeNs2 = configAddedTimeNs + 40 * NS_PER_SEC;
455     const int64_t gaugeEventTimeNs3 = configAddedTimeNs + 60 * NS_PER_SEC;
456     const int64_t gaugeEventTimeNs4 = configAddedTimeNs + 100 * NS_PER_SEC;
457     const int64_t gaugeEventTimeNs5 = configAddedTimeNs + 110 * NS_PER_SEC;
458     const int64_t gaugeEventTimeNs6 = configAddedTimeNs + 150 * NS_PER_SEC;
459 
460     std::vector<std::unique_ptr<LogEvent>> events;
461     events.push_back(CreateAppCrashOccurredEvent(gaugeEventTimeNs1, appUid1));  // 0:30
462     events.push_back(CreateAppCrashOccurredEvent(gaugeEventTimeNs2, appUid2));  // 0:50
463     events.push_back(CreateAppCrashOccurredEvent(gaugeEventTimeNs3, appUid3));  // 1:10
464     events.push_back(CreateAppCrashOccurredEvent(gaugeEventTimeNs4, appUid1));  // 1:50
465     events.push_back(CreateAppCrashOccurredEvent(gaugeEventTimeNs5, appUid2));  // 2:00
466     events.push_back(CreateAppCrashOccurredEvent(gaugeEventTimeNs6, appUid3));  // 2:40
467 
468     // Send log events to StatsLogProcessor.
469     for (auto& event : events) {
470         processor->OnLogEvent(event.get());
471     }
472 
473     ConfigMetricsReportList reports;
474     vector<uint8_t> buffer;
475     processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
476                             FAST, &buffer);
477     EXPECT_TRUE(buffer.size() > 0);
478     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
479     backfillDimensionPath(&reports);
480     backfillStringInReport(&reports);
481     backfillStartEndTimestamp(&reports);
482     backfillAggregatedAtoms(&reports);
483 
484     ASSERT_EQ(1, reports.reports_size());
485     ASSERT_EQ(1, reports.reports(0).metrics_size());
486     EXPECT_TRUE(reports.reports(0).metrics(0).has_gauge_metrics());
487     StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
488     sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
489     ASSERT_EQ(2, gaugeMetrics.data_size());
490 
491     // Only Uid 1 and 3 are logged. (odd hash value) + (offset of 5) % (shard count of 2) = 0
492     GaugeMetricData data = gaugeMetrics.data(0);
493     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, appUid1);
494     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
495                              configAddedTimeNs + bucketSizeNs,
496                              {gaugeEventTimeNs1, gaugeEventTimeNs4});
497 
498     data = gaugeMetrics.data(1);
499     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, appUid3);
500     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
501                              configAddedTimeNs + bucketSizeNs,
502                              {gaugeEventTimeNs3, gaugeEventTimeNs6});
503 }
504 
TEST_F(GaugeMetricE2ePushedTest,TestPushedGaugeMetricSampling)505 TEST_F(GaugeMetricE2ePushedTest, TestPushedGaugeMetricSampling) {
506     // Initiating StatsdStats at the start of this test, so it doesn't call rand() during the test.
507     StatsdStats::getInstance();
508     // Set srand seed to make rand deterministic for testing.
509     srand(0);
510 
511     StatsdConfig config;
512     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
513 
514     AtomMatcher appCrashMatcher =
515             CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
516     *config.add_atom_matcher() = appCrashMatcher;
517 
518     GaugeMetric sampledGaugeMetric =
519             createGaugeMetric("GaugeSampledAppCrashesPerUid", appCrashMatcher.id(),
520                               GaugeMetric::FIRST_N_SAMPLES, nullopt, nullopt);
521     *sampledGaugeMetric.mutable_dimensions_in_what() =
522             CreateDimensions(util::APP_CRASH_OCCURRED, {1 /* uid */});
523     sampledGaugeMetric.set_sampling_percentage(50);
524     *config.add_gauge_metric() = sampledGaugeMetric;
525 
526     const int64_t configAddedTimeNs = 10 * NS_PER_SEC;  // 0:10
527     const int64_t bucketSizeNs =
528             TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000LL * 1000LL;
529 
530     int uid = 12345;
531     int64_t cfgId = 98765;
532     ConfigKey cfgKey(uid, cfgId);
533 
534     sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
535             configAddedTimeNs, configAddedTimeNs, config, cfgKey, nullptr, 0, new UidMap());
536 
537     std::vector<std::unique_ptr<LogEvent>> events;
538     for (int i = 0; i < 10; i++) {
539         events.push_back(
540                 CreateAppCrashOccurredEvent(configAddedTimeNs + (10 * i * NS_PER_SEC), 1000 + i));
541     }
542 
543     // Send log events to StatsLogProcessor.
544     for (auto& event : events) {
545         processor->OnLogEvent(event.get());
546     }
547 
548     ConfigMetricsReportList reports;
549     vector<uint8_t> buffer;
550     processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
551                             FAST, &buffer);
552     EXPECT_TRUE(buffer.size() > 0);
553     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
554     backfillDimensionPath(&reports);
555     backfillStringInReport(&reports);
556     backfillStartEndTimestamp(&reports);
557     backfillAggregatedAtoms(&reports);
558 
559     ASSERT_EQ(1, reports.reports_size());
560     ASSERT_EQ(1, reports.reports(0).metrics_size());
561     EXPECT_TRUE(reports.reports(0).metrics(0).has_gauge_metrics());
562     StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
563     sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
564     ASSERT_EQ(5, gaugeMetrics.data_size());
565 
566     GaugeMetricData data = gaugeMetrics.data(0);
567     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1000);
568     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
569                              configAddedTimeNs + bucketSizeNs, {configAddedTimeNs});
570 
571     data = gaugeMetrics.data(1);
572     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1002);
573     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
574                              configAddedTimeNs + bucketSizeNs,
575                              {configAddedTimeNs + (10 * 2 * NS_PER_SEC)});
576 
577     data = gaugeMetrics.data(2);
578     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1003);
579     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
580                              configAddedTimeNs + bucketSizeNs,
581                              {configAddedTimeNs + (10 * 3 * NS_PER_SEC)});
582 
583     data = gaugeMetrics.data(3);
584     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1007);
585     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
586                              configAddedTimeNs + bucketSizeNs,
587                              {configAddedTimeNs + (10 * 7 * NS_PER_SEC)});
588 
589     data = gaugeMetrics.data(4);
590     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1009);
591     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
592                              configAddedTimeNs + bucketSizeNs,
593                              {configAddedTimeNs + (10 * 9 * NS_PER_SEC)});
594 }
595 
TEST_F(GaugeMetricE2ePushedTest,TestPushedGaugeMetricSamplingWithDimensionalSampling)596 TEST_F(GaugeMetricE2ePushedTest, TestPushedGaugeMetricSamplingWithDimensionalSampling) {
597     ShardOffsetProvider::getInstance().setShardOffset(5);
598     // Initiating StatsdStats at the start of this test, so it doesn't call rand() during the test.
599     StatsdStats::getInstance();
600     // Set srand seed to make rand deterministic for testing.
601     srand(0);
602 
603     StatsdConfig config;
604     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
605 
606     AtomMatcher appCrashMatcher =
607             CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
608     *config.add_atom_matcher() = appCrashMatcher;
609 
610     GaugeMetric sampledGaugeMetric =
611             createGaugeMetric("GaugeSampledAppCrashesPerUid", appCrashMatcher.id(),
612                               GaugeMetric::FIRST_N_SAMPLES, nullopt, nullopt);
613     *sampledGaugeMetric.mutable_dimensions_in_what() =
614             CreateDimensions(util::APP_CRASH_OCCURRED, {1 /* uid */});
615     *sampledGaugeMetric.mutable_dimensional_sampling_info()->mutable_sampled_what_field() =
616             CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
617     sampledGaugeMetric.mutable_dimensional_sampling_info()->set_shard_count(2);
618     sampledGaugeMetric.set_sampling_percentage(50);
619     *config.add_gauge_metric() = sampledGaugeMetric;
620 
621     const int64_t configAddedTimeNs = 10 * NS_PER_SEC;  // 0:10
622     const int64_t bucketSizeNs =
623             TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000LL * 1000LL;
624 
625     int uid = 12345;
626     int64_t cfgId = 98765;
627     ConfigKey cfgKey(uid, cfgId);
628 
629     sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
630             configAddedTimeNs, configAddedTimeNs, config, cfgKey, nullptr, 0, new UidMap());
631 
632     std::vector<std::unique_ptr<LogEvent>> events;
633     for (int i = 0; i < 30; i++) {
634         // Generate events with three different app uids: 1001, 1002, 1003.
635         events.push_back(CreateAppCrashOccurredEvent(configAddedTimeNs + (10 * i * NS_PER_SEC),
636                                                      1001 + (i % 3)));
637     }
638 
639     // Send log events to StatsLogProcessor.
640     for (auto& event : events) {
641         processor->OnLogEvent(event.get());
642     }
643 
644     ConfigMetricsReportList reports;
645     vector<uint8_t> buffer;
646     processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
647                             FAST, &buffer);
648     EXPECT_TRUE(buffer.size() > 0);
649     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
650     backfillDimensionPath(&reports);
651     backfillStringInReport(&reports);
652     backfillStartEndTimestamp(&reports);
653     backfillAggregatedAtoms(&reports);
654 
655     ASSERT_EQ(1, reports.reports_size());
656     ASSERT_EQ(1, reports.reports(0).metrics_size());
657     EXPECT_TRUE(reports.reports(0).metrics(0).has_gauge_metrics());
658     StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
659     sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
660     ASSERT_EQ(2, gaugeMetrics.data_size());
661 
662     // Only Uid 1 and 3 are logged. (odd hash value) + (offset of 5) % (shard count of 2) = 0
663     GaugeMetricData data = gaugeMetrics.data(0);
664     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1001);
665     ValidateGaugeBucketTimes(
666             data.bucket_info(0), configAddedTimeNs, configAddedTimeNs + bucketSizeNs,
667             {10 * NS_PER_SEC, 40 * NS_PER_SEC, 220 * NS_PER_SEC, 280 * NS_PER_SEC});
668 
669     data = gaugeMetrics.data(1);
670     ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1003);
671     ValidateGaugeBucketTimes(data.bucket_info(0), configAddedTimeNs,
672                              configAddedTimeNs + bucketSizeNs,
673                              {60 * NS_PER_SEC, 120 * NS_PER_SEC, 150 * NS_PER_SEC, 180 * NS_PER_SEC,
674                               210 * NS_PER_SEC, 300 * NS_PER_SEC});
675 }
676 
677 #else
678 GTEST_LOG_(INFO) << "This test does nothing.\n";
679 #endif
680 
681 }  // namespace statsd
682 }  // namespace os
683 }  // namespace android
684