• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <android/binder_ibinder.h>
16 #include <android/binder_interface_utils.h>
17 #include <gtest/gtest.h>
18 
19 #include <vector>
20 
21 #include "src/StatsLogProcessor.h"
22 #include "src/StatsService.h"
23 #include "src/stats_log_util.h"
24 #include "tests/statsd_test_util.h"
25 
26 using::ndk::SharedRefBase;
27 using std::shared_ptr;
28 
29 namespace android {
30 namespace os {
31 namespace statsd {
32 
33 #ifdef __ANDROID__
34 namespace {
35 const string kApp1 = "app1.sharing.1";
36 const int kConfigKey = 789130123;  // Randomly chosen to avoid collisions with existing configs.
37 const int kCallingUid = 0; // Randomly chosen
38 
SendConfig(shared_ptr<StatsService> & service,const StatsdConfig & config)39 void SendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) {
40     string str;
41     config.SerializeToString(&str);
42     std::vector<uint8_t> configAsVec(str.begin(), str.end());
43     service->addConfiguration(kConfigKey, configAsVec, kCallingUid);
44 }
45 
GetReports(sp<StatsLogProcessor> processor,int64_t timestamp,bool include_current=false)46 ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
47                                bool include_current = false) {
48     vector<uint8_t> output;
49     ConfigKey configKey(AIBinder_getCallingUid(), kConfigKey);
50     processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
51                             true /* erase_data */, ADB_DUMP, NO_TIME_CONSTRAINTS, &output);
52     ConfigMetricsReportList reports;
53     reports.ParseFromArray(output.data(), output.size());
54     EXPECT_EQ(1, reports.reports_size());
55     return reports.reports(kCallingUid);
56 }
57 
MakeCountMetricConfig(const std::optional<bool> splitBucket)58 StatsdConfig MakeCountMetricConfig(const std::optional<bool> splitBucket) {
59     StatsdConfig config;
60     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
61 
62     auto appCrashMatcher = CreateProcessCrashAtomMatcher();
63     *config.add_atom_matcher() = appCrashMatcher;
64     auto countMetric = config.add_count_metric();
65     countMetric->set_id(StringToId("AppCrashes"));
66     countMetric->set_what(appCrashMatcher.id());
67     countMetric->set_bucket(FIVE_MINUTES);
68     if (splitBucket.has_value()) {
69         countMetric->set_split_bucket_for_app_upgrade(splitBucket.value());
70     }
71     return config;
72 }
73 
MakeValueMetricConfig(int64_t minTime)74 StatsdConfig MakeValueMetricConfig(int64_t minTime) {
75     StatsdConfig config;
76     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
77     config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
78 
79     auto pulledAtomMatcher =
80             CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
81     *config.add_atom_matcher() = pulledAtomMatcher;
82     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
83     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
84 
85     auto valueMetric = config.add_value_metric();
86     valueMetric->set_id(123456);
87     valueMetric->set_what(pulledAtomMatcher.id());
88     *valueMetric->mutable_value_field() =
89             CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
90     *valueMetric->mutable_dimensions_in_what() =
91             CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
92     valueMetric->set_bucket(FIVE_MINUTES);
93     valueMetric->set_min_bucket_size_nanos(minTime);
94     valueMetric->set_use_absolute_value_on_reset(true);
95     valueMetric->set_skip_zero_diff_output(false);
96     valueMetric->set_split_bucket_for_app_upgrade(true);
97     return config;
98 }
99 
MakeGaugeMetricConfig(int64_t minTime)100 StatsdConfig MakeGaugeMetricConfig(int64_t minTime) {
101     StatsdConfig config;
102     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
103     config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
104 
105     auto pulledAtomMatcher =
106                 CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
107     *config.add_atom_matcher() = pulledAtomMatcher;
108     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
109     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
110 
111     auto gaugeMetric = config.add_gauge_metric();
112     gaugeMetric->set_id(123456);
113     gaugeMetric->set_what(pulledAtomMatcher.id());
114     gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
115     *gaugeMetric->mutable_dimensions_in_what() =
116             CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
117     gaugeMetric->set_bucket(FIVE_MINUTES);
118     gaugeMetric->set_min_bucket_size_nanos(minTime);
119     gaugeMetric->set_split_bucket_for_app_upgrade(true);
120     return config;
121 }
122 }  // anonymous namespace
123 
TEST(PartialBucketE2eTest,TestCountMetricWithoutSplit)124 TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
125     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
126     SendConfig(service, MakeCountMetricConfig({true}));
127     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
128                                              // initialized with.
129 
130     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
131     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 2, 100).get());
132 
133     ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
134     // Expect no metrics since the bucket has not finished yet.
135     ASSERT_EQ(1, report.metrics_size());
136     ASSERT_EQ(0, report.metrics(0).count_metrics().data_size());
137 }
138 
TEST(PartialBucketE2eTest,TestCountMetricNoSplitOnNewApp)139 TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
140     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
141     SendConfig(service, MakeCountMetricConfig({true}));
142     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
143                                              // initialized with.
144 
145     // Force the uidmap to update at timestamp 2.
146     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
147     // This is a new installation, so there shouldn't be a split (should be same as the without
148     // split case).
149     service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
150                                 String16(""), /* certificateHash */ {});
151     // Goes into the second bucket.
152     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
153 
154     ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
155     ASSERT_EQ(1, report.metrics_size());
156     ASSERT_EQ(0, report.metrics(0).count_metrics().data_size());
157 }
158 
TEST(PartialBucketE2eTest,TestCountMetricSplitOnUpgrade)159 TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
160     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
161     SendConfig(service, MakeCountMetricConfig({true}));
162     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
163                                              // initialized with.
164     service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
165                                 {String16("")}, /* certificateHash */ {{}});
166 
167     // Force the uidmap to update at timestamp 2.
168     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
169     service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
170                                 String16(""), /* certificateHash */ {});
171     // Goes into the second bucket.
172     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
173 
174     ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
175     backfillStartEndTimestamp(&report);
176 
177     ASSERT_EQ(1, report.metrics_size());
178     ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
179     ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
180     EXPECT_TRUE(report.metrics(0)
181                         .count_metrics()
182                         .data(0)
183                         .bucket_info(0)
184                         .has_start_bucket_elapsed_nanos());
185     EXPECT_TRUE(report.metrics(0)
186                         .count_metrics()
187                         .data(0)
188                         .bucket_info(0)
189                         .has_end_bucket_elapsed_nanos());
190     EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
191 }
192 
TEST(PartialBucketE2eTest,TestCountMetricSplitOnRemoval)193 TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
194     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
195     SendConfig(service, MakeCountMetricConfig({true}));
196     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
197                                              // initialized with.
198     service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
199                                 {String16("")}, /* certificateHash */ {{}});
200 
201     // Force the uidmap to update at timestamp 2.
202     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
203     service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
204     // Goes into the second bucket.
205     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
206 
207     ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
208     backfillStartEndTimestamp(&report);
209 
210     ASSERT_EQ(1, report.metrics_size());
211     ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
212     ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
213     EXPECT_TRUE(report.metrics(0)
214                         .count_metrics()
215                         .data(0)
216                         .bucket_info(0)
217                         .has_start_bucket_elapsed_nanos());
218     EXPECT_TRUE(report.metrics(0)
219                         .count_metrics()
220                         .data(0)
221                         .bucket_info(0)
222                         .has_end_bucket_elapsed_nanos());
223     EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
224 }
225 
TEST(PartialBucketE2eTest,TestCountMetricSplitOnBoot)226 TEST(PartialBucketE2eTest, TestCountMetricSplitOnBoot) {
227     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
228     SendConfig(service, MakeCountMetricConfig(std::nullopt));
229     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
230                                              // initialized with.
231 
232     // Goes into the first bucket
233     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + NS_PER_SEC, 100).get());
234     int64_t bootCompleteTimeNs = start + 2 * NS_PER_SEC;
235     service->mProcessor->onStatsdInitCompleted(bootCompleteTimeNs);
236     // Goes into the second bucket.
237     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3 * NS_PER_SEC, 100).get());
238 
239     ConfigMetricsReport report = GetReports(service->mProcessor, start + 4 * NS_PER_SEC);
240     backfillStartEndTimestamp(&report);
241 
242     ASSERT_EQ(1, report.metrics_size());
243     ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
244     ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
245     EXPECT_TRUE(report.metrics(0)
246                         .count_metrics()
247                         .data(0)
248                         .bucket_info(0)
249                         .has_start_bucket_elapsed_nanos());
250     EXPECT_EQ(MillisToNano(NanoToMillis(bootCompleteTimeNs)),
251               report.metrics(0).count_metrics().data(0).bucket_info(0).end_bucket_elapsed_nanos());
252     EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
253 }
254 
TEST(PartialBucketE2eTest,TestCountMetricNoSplitOnUpgradeWhenDisabled)255 TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnUpgradeWhenDisabled) {
256     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
257     StatsdConfig config = MakeCountMetricConfig({false});
258     SendConfig(service, config);
259     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
260                                              // initialized with.
261     service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
262                                 {String16("")}, /* certificateHash */ {{}});
263 
264     // Force the uidmap to update at timestamp 2.
265     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
266     service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
267                                 String16(""), /* certificateHash */ {});
268     // Still goes into the first bucket.
269     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
270 
271     ConfigMetricsReport report =
272             GetReports(service->mProcessor, start + 4, /*include_current=*/true);
273     backfillStartEndTimestamp(&report);
274 
275     ASSERT_EQ(1, report.metrics_size());
276     ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
277     ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
278     const CountBucketInfo& bucketInfo = report.metrics(0).count_metrics().data(0).bucket_info(0);
279     EXPECT_EQ(bucketInfo.end_bucket_elapsed_nanos(), MillisToNano(NanoToMillis(start + 4)));
280     EXPECT_EQ(bucketInfo.count(), 2);
281 }
282 
TEST(PartialBucketE2eTest,TestValueMetricWithoutMinPartialBucket)283 TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
284     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
285     service->mPullerManager->RegisterPullAtomCallback(
286             /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
287             SharedRefBase::make<FakeSubsystemSleepCallback>());
288     // Partial buckets don't occur when app is first installed.
289     service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""),
290                                 /* certificateHash */ {});
291     SendConfig(service, MakeValueMetricConfig(0));
292     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
293                                              // initialized with.
294 
295     service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
296     int64_t appUpgradeTimeNs = 5 * 60 * NS_PER_SEC + start + 2 * NS_PER_SEC;
297     service->mUidMap->updateApp(appUpgradeTimeNs, String16(kApp1.c_str()), 1, 2, String16("v2"),
298                                 String16(""), /* certificateHash */ {});
299 
300     ConfigMetricsReport report =
301             GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC);
302     backfillStartEndTimestamp(&report);
303 
304     ASSERT_EQ(1, report.metrics_size());
305     ASSERT_EQ(0, report.metrics(0).value_metrics().skipped_size());
306 
307     // The fake subsystem state sleep puller returns two atoms.
308     ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
309     ASSERT_EQ(2, report.metrics(0).value_metrics().data(0).bucket_info_size());
310     EXPECT_EQ(MillisToNano(NanoToMillis(appUpgradeTimeNs)),
311               report.metrics(0).value_metrics().data(0).bucket_info(1).end_bucket_elapsed_nanos());
312 }
313 
TEST(PartialBucketE2eTest,TestValueMetricWithMinPartialBucket)314 TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
315     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
316     service->mPullerManager->RegisterPullAtomCallback(
317             /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
318             SharedRefBase::make<FakeSubsystemSleepCallback>());
319     // Partial buckets don't occur when app is first installed.
320     service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""),
321                                 /* certificateHash */ {});
322     SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
323     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
324                                              // initialized with.
325 
326     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2 * NS_PER_SEC;
327     service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
328     service->mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
329                                 String16(""), /* certificateHash */ {});
330 
331     ConfigMetricsReport report =
332             GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC);
333     backfillStartEndTimestamp(&report);
334 
335     ASSERT_EQ(1, report.metrics_size());
336     ASSERT_EQ(1, report.metrics(0).value_metrics().skipped_size());
337     EXPECT_TRUE(report.metrics(0).value_metrics().skipped(0).has_start_bucket_elapsed_nanos());
338     // Can't test the start time since it will be based on the actual time when the pulling occurs.
339     EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
340               report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
341 
342     ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
343     ASSERT_EQ(1, report.metrics(0).value_metrics().data(0).bucket_info_size());
344 }
345 
TEST(PartialBucketE2eTest,TestValueMetricOnBootWithoutMinPartialBucket)346 TEST(PartialBucketE2eTest, TestValueMetricOnBootWithoutMinPartialBucket) {
347     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
348     // Initial pull will fail since puller is not registered.
349     SendConfig(service, MakeValueMetricConfig(0));
350     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
351                                              // initialized with.
352 
353     service->mPullerManager->RegisterPullAtomCallback(
354             /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
355             SharedRefBase::make<FakeSubsystemSleepCallback>());
356 
357     int64_t bootCompleteTimeNs = start + NS_PER_SEC;
358     service->mProcessor->onStatsdInitCompleted(bootCompleteTimeNs);
359 
360     service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
361 
362     ConfigMetricsReport report = GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100);
363     backfillStartEndTimestamp(&report);
364 
365     // First bucket is dropped due to the initial pull failing
366     ASSERT_EQ(1, report.metrics_size());
367     ASSERT_EQ(1, report.metrics(0).value_metrics().skipped_size());
368     EXPECT_EQ(MillisToNano(NanoToMillis(bootCompleteTimeNs)),
369               report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
370 
371     // The fake subsystem state sleep puller returns two atoms.
372     ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
373     ASSERT_EQ(1, report.metrics(0).value_metrics().data(0).bucket_info_size());
374     EXPECT_EQ(
375             MillisToNano(NanoToMillis(bootCompleteTimeNs)),
376             report.metrics(0).value_metrics().data(0).bucket_info(0).start_bucket_elapsed_nanos());
377 }
378 
TEST(PartialBucketE2eTest,TestGaugeMetricWithoutMinPartialBucket)379 TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
380     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
381     service->mPullerManager->RegisterPullAtomCallback(
382             /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
383             SharedRefBase::make<FakeSubsystemSleepCallback>());
384     // Partial buckets don't occur when app is first installed.
385     service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""),
386                                 /* certificateHash */ {});
387     SendConfig(service, MakeGaugeMetricConfig(0));
388     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
389                                              // initialized with.
390 
391     service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
392     service->mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
393                                 String16("v2"), String16(""), /* certificateHash */ {});
394 
395     ConfigMetricsReport report = GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100);
396     backfillStartEndTimestamp(&report);
397     ASSERT_EQ(1, report.metrics_size());
398     ASSERT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
399     // The fake subsystem state sleep puller returns two atoms.
400     ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
401     ASSERT_EQ(2, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
402 }
403 
TEST(PartialBucketE2eTest,TestGaugeMetricWithMinPartialBucket)404 TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
405     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
406     // Partial buckets don't occur when app is first installed.
407     service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""),
408                                 /* certificateHash */ {});
409     service->mPullerManager->RegisterPullAtomCallback(
410             /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
411             SharedRefBase::make<FakeSubsystemSleepCallback>());
412     SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
413     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
414                                              // initialized with.
415 
416     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
417     service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
418     service->mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
419                                 String16(""), /* certificateHash */ {});
420 
421     ConfigMetricsReport report =
422             GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC);
423     backfillStartEndTimestamp(&report);
424     ASSERT_EQ(1, report.metrics_size());
425     ASSERT_EQ(1, report.metrics(0).gauge_metrics().skipped_size());
426     // Can't test the start time since it will be based on the actual time when the pulling occurs.
427     EXPECT_TRUE(report.metrics(0).gauge_metrics().skipped(0).has_start_bucket_elapsed_nanos());
428     EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
429               report.metrics(0).gauge_metrics().skipped(0).end_bucket_elapsed_nanos());
430     ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
431     ASSERT_EQ(1, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
432 }
433 
TEST(PartialBucketE2eTest,TestGaugeMetricOnBootWithoutMinPartialBucket)434 TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket) {
435     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
436     // Initial pull will fail since puller hasn't been registered.
437     SendConfig(service, MakeGaugeMetricConfig(0));
438     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
439                                              // initialized with.
440 
441     service->mPullerManager->RegisterPullAtomCallback(
442             /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
443             SharedRefBase::make<FakeSubsystemSleepCallback>());
444 
445     int64_t bootCompleteTimeNs = start + NS_PER_SEC;
446     service->mProcessor->onStatsdInitCompleted(bootCompleteTimeNs);
447 
448     service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
449 
450     ConfigMetricsReport report = GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100);
451     backfillStartEndTimestamp(&report);
452 
453     ASSERT_EQ(1, report.metrics_size());
454     ASSERT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
455     // The fake subsystem state sleep puller returns two atoms.
456     ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
457     // No data in the first bucket, so nothing is reported
458     ASSERT_EQ(1, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
459     EXPECT_EQ(
460             MillisToNano(NanoToMillis(bootCompleteTimeNs)),
461             report.metrics(0).gauge_metrics().data(0).bucket_info(0).start_bucket_elapsed_nanos());
462 }
463 
TEST(PartialBucketE2eTest,TestCountMetricNoSplitByDefault)464 TEST(PartialBucketE2eTest, TestCountMetricNoSplitByDefault) {
465     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
466     StatsdConfig config = MakeCountMetricConfig({nullopt});  // Do not set the value in the metric.
467     SendConfig(service, config);
468     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
469                                              // initialized with.
470     service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
471                                 {String16("")}, /* certificateHash */ {{}});
472 
473     // Force the uidmap to update at timestamp 2.
474     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
475     service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
476                                 String16(""), /* certificateHash */ {});
477     // Still goes into the first bucket.
478     service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
479 
480     ConfigMetricsReport report =
481             GetReports(service->mProcessor, start + 4, /*include_current=*/true);
482     backfillStartEndTimestamp(&report);
483 
484     ASSERT_EQ(1, report.metrics_size());
485     ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
486     ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
487     const CountBucketInfo& bucketInfo = report.metrics(0).count_metrics().data(0).bucket_info(0);
488     EXPECT_EQ(bucketInfo.end_bucket_elapsed_nanos(), MillisToNano(NanoToMillis(start + 4)));
489     EXPECT_EQ(bucketInfo.count(), 2);
490 }
491 
492 #else
493 GTEST_LOG_(INFO) << "This test does nothing.\n";
494 #endif
495 
496 }  // namespace statsd
497 }  // namespace os
498 }  // namespace android
499