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 "src/StatsLogProcessor.h"
18#include "src/stats_log_util.h"
19#include "tests/statsd_test_util.h"
20
21#include <vector>
22
23namespace android {
24namespace os {
25namespace statsd {
26
27#ifdef __ANDROID__
28
29namespace {
30
31StatsdConfig CreateStatsdConfig() {
32    StatsdConfig config;
33    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
34    auto temperatureAtomMatcher = CreateTemperatureAtomMatcher();
35    *config.add_atom_matcher() = temperatureAtomMatcher;
36    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
37    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
38
39    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
40    *config.add_predicate() = screenIsOffPredicate;
41
42    auto valueMetric = config.add_value_metric();
43    valueMetric->set_id(123456);
44    valueMetric->set_what(temperatureAtomMatcher.id());
45    valueMetric->set_condition(screenIsOffPredicate.id());
46    *valueMetric->mutable_value_field() =
47        CreateDimensions(android::util::TEMPERATURE, {3/* temperature degree field */ });
48    *valueMetric->mutable_dimensions_in_what() =
49        CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
50    valueMetric->set_bucket(FIVE_MINUTES);
51    valueMetric->set_use_absolute_value_on_reset(true);
52    return config;
53}
54
55}  // namespace
56
57TEST(ValueMetricE2eTest, TestPulledEvents) {
58    auto config = CreateStatsdConfig();
59    int64_t baseTimeNs = 10 * NS_PER_SEC;
60    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
61    int64_t bucketSizeNs =
62        TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
63
64    ConfigKey cfgKey;
65    auto processor = CreateStatsLogProcessor(
66        baseTimeNs, configAddedTimeNs, config, cfgKey);
67    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
68    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
69    processor->mStatsPullerManager.ForceClearPullerCache();
70
71    int startBucketNum = processor->mMetricsManagers.begin()->second->
72            mAllMetricProducers[0]->getCurrentBucketNum();
73    EXPECT_GT(startBucketNum, (int64_t)0);
74
75    // When creating the config, the gauge metric producer should register the alarm at the
76    // end of the current bucket.
77    EXPECT_EQ((size_t)1, StatsPullerManagerImpl::GetInstance().mReceivers.size());
78    EXPECT_EQ(bucketSizeNs,
79              StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
80                    second.front().intervalNs);
81    int64_t& expectedPullTimeNs = StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
82            second.front().nextPullTimeNs;
83    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
84
85    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
86                                                        configAddedTimeNs + 55);
87    processor->OnLogEvent(screenOffEvent.get());
88
89    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
90                                                       configAddedTimeNs + 65);
91    processor->OnLogEvent(screenOnEvent.get());
92
93    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
94                                                   configAddedTimeNs + 75);
95    processor->OnLogEvent(screenOffEvent.get());
96
97    // Pulling alarm arrives on time and reset the sequential pulling alarm.
98    processor->informPullAlarmFired(expectedPullTimeNs + 1);
99    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
100
101    processor->informPullAlarmFired(expectedPullTimeNs + 1);
102
103    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
104                                                       configAddedTimeNs + 2 * bucketSizeNs + 15);
105    processor->OnLogEvent(screenOnEvent.get());
106
107    processor->informPullAlarmFired(expectedPullTimeNs + 1);
108
109    processor->informPullAlarmFired(expectedPullTimeNs + 1);
110
111    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
112                                                   configAddedTimeNs + 4 * bucketSizeNs + 11);
113    processor->OnLogEvent(screenOffEvent.get());
114
115    processor->informPullAlarmFired(expectedPullTimeNs + 1);
116
117    processor->informPullAlarmFired(expectedPullTimeNs + 1);
118
119    ConfigMetricsReportList reports;
120    vector<uint8_t> buffer;
121    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
122                            &buffer);
123    EXPECT_TRUE(buffer.size() > 0);
124    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
125    backfillDimensionPath(&reports);
126    backfillStringInReport(&reports);
127    backfillStartEndTimestamp(&reports);
128    EXPECT_EQ(1, reports.reports_size());
129    EXPECT_EQ(1, reports.reports(0).metrics_size());
130    StatsLogReport::ValueMetricDataWrapper valueMetrics;
131    sortMetricDataByDimensionsValue(
132            reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
133    EXPECT_GT((int)valueMetrics.data_size(), 1);
134
135    auto data = valueMetrics.data(0);
136    EXPECT_EQ(android::util::TEMPERATURE, data.dimensions_in_what().field());
137    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
138    EXPECT_EQ(2 /* sensor name field */,
139              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
140    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
141    EXPECT_EQ(5, data.bucket_info_size());
142
143    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
144    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
145    EXPECT_TRUE(data.bucket_info(0).has_value());
146
147    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
148    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
149    EXPECT_TRUE(data.bucket_info(1).has_value());
150
151    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
152    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
153    EXPECT_TRUE(data.bucket_info(2).has_value());
154
155    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
156    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
157    EXPECT_TRUE(data.bucket_info(3).has_value());
158
159    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
160    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
161    EXPECT_TRUE(data.bucket_info(4).has_value());
162}
163
164TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
165    auto config = CreateStatsdConfig();
166    int64_t baseTimeNs = 10 * NS_PER_SEC;
167    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
168    int64_t bucketSizeNs =
169        TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
170
171    ConfigKey cfgKey;
172    auto processor = CreateStatsLogProcessor(
173        baseTimeNs, configAddedTimeNs, config, cfgKey);
174    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
175    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
176    processor->mStatsPullerManager.ForceClearPullerCache();
177
178    int startBucketNum = processor->mMetricsManagers.begin()->second->
179            mAllMetricProducers[0]->getCurrentBucketNum();
180    EXPECT_GT(startBucketNum, (int64_t)0);
181
182    // When creating the config, the gauge metric producer should register the alarm at the
183    // end of the current bucket.
184    EXPECT_EQ((size_t)1, StatsPullerManagerImpl::GetInstance().mReceivers.size());
185    EXPECT_EQ(bucketSizeNs,
186              StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
187                    second.front().intervalNs);
188    int64_t& expectedPullTimeNs = StatsPullerManagerImpl::GetInstance().mReceivers.begin()->
189            second.front().nextPullTimeNs;
190    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
191
192    // Screen off/on/off events.
193    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
194                                                        configAddedTimeNs + 55);
195    processor->OnLogEvent(screenOffEvent.get());
196
197    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
198                                                       configAddedTimeNs + 65);
199    processor->OnLogEvent(screenOnEvent.get());
200
201    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
202                                                   configAddedTimeNs + 75);
203    processor->OnLogEvent(screenOffEvent.get());
204
205    // Pulling alarm arrives late by 2 buckets and 1 ns.
206    processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
207    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
208
209    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
210                                                       configAddedTimeNs + 4 * bucketSizeNs + 65);
211    processor->OnLogEvent(screenOnEvent.get());
212
213    // Pulling alarm arrives late by one bucket size + 21ns.
214    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
215    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
216
217    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
218                                                   configAddedTimeNs + 6 * bucketSizeNs + 31);
219    processor->OnLogEvent(screenOffEvent.get());
220
221    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
222    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
223
224    processor->informPullAlarmFired(expectedPullTimeNs + 1);
225    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
226
227    ConfigMetricsReportList reports;
228    vector<uint8_t> buffer;
229    processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, ADB_DUMP,
230                            &buffer);
231    EXPECT_TRUE(buffer.size() > 0);
232    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
233    backfillDimensionPath(&reports);
234    backfillStringInReport(&reports);
235    backfillStartEndTimestamp(&reports);
236    EXPECT_EQ(1, reports.reports_size());
237    EXPECT_EQ(1, reports.reports(0).metrics_size());
238    StatsLogReport::ValueMetricDataWrapper valueMetrics;
239    sortMetricDataByDimensionsValue(
240            reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
241    EXPECT_GT((int)valueMetrics.data_size(), 1);
242
243    auto data = valueMetrics.data(0);
244    EXPECT_EQ(android::util::TEMPERATURE, data.dimensions_in_what().field());
245    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
246    EXPECT_EQ(2 /* sensor name field */,
247              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
248    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
249    EXPECT_EQ(3, data.bucket_info_size());
250
251    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
252    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
253    EXPECT_TRUE(data.bucket_info(0).has_value());
254
255    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
256    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
257    EXPECT_TRUE(data.bucket_info(1).has_value());
258
259    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
260    EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
261    EXPECT_TRUE(data.bucket_info(2).has_value());
262}
263
264#else
265GTEST_LOG_(INFO) << "This test does nothing.\n";
266#endif
267
268}  // namespace statsd
269}  // namespace os
270}  // namespace android
271