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