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 <iostream>
22#include <vector>
23
24namespace android {
25namespace os {
26namespace statsd {
27
28#ifdef __ANDROID__
29
30namespace {
31
32StatsdConfig CreateStatsdConfig(const Position position) {
33    StatsdConfig config;
34    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
35    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
36    auto attributionNodeMatcher =
37        wakelockAcquireMatcher.mutable_simple_atom_matcher()->add_field_value_matcher();
38    attributionNodeMatcher->set_field(1);
39    attributionNodeMatcher->set_position(Position::ANY);
40    auto uidMatcher = attributionNodeMatcher->mutable_matches_tuple()->add_field_value_matcher();
41    uidMatcher->set_field(1);  // uid field.
42    uidMatcher->set_eq_string("com.android.gmscore");
43
44    *config.add_atom_matcher() = wakelockAcquireMatcher;
45
46    auto countMetric = config.add_count_metric();
47    countMetric->set_id(123456);
48    countMetric->set_what(wakelockAcquireMatcher.id());
49    *countMetric->mutable_dimensions_in_what() =
50        CreateAttributionUidAndTagDimensions(
51            android::util::WAKELOCK_STATE_CHANGED, {position});
52    countMetric->set_bucket(FIVE_MINUTES);
53    return config;
54}
55
56}  // namespace
57
58TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
59    auto config = CreateStatsdConfig(Position::FIRST);
60    int64_t bucketStartTimeNs = 10000000000;
61    int64_t bucketSizeNs =
62        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
63
64    ConfigKey cfgKey;
65    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
66    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
67    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
68
69    // Here it assumes that GMS core has two uids.
70    processor->getUidMap()->updateMap(
71            1, {222, 444, 111, 333}, {1, 1, 2, 2},
72            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
73             String16("APP3")});
74
75    // GMS core node is in the middle.
76    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
77                                                          CreateAttribution(222, "GMSCoreModule1"),
78                                                          CreateAttribution(333, "App3")};
79
80    // GMS core node is the last one.
81    std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
82                                                          CreateAttribution(333, "App3"),
83                                                          CreateAttribution(222, "GMSCoreModule1")};
84
85    // GMS core node is the first one.
86    std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
87                                                          CreateAttribution(333, "App3")};
88
89    // Single GMS core node.
90    std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
91
92    // GMS core has another uid.
93    std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
94                                                          CreateAttribution(444, "GMSCoreModule2"),
95                                                          CreateAttribution(333, "App3")};
96
97    // Multiple GMS core nodes.
98    std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
99                                                          CreateAttribution(222, "GMSCoreModule1")};
100
101    // No GMS core nodes.
102    std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
103                                                          CreateAttribution(333, "App3")};
104    std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
105
106    // GMS core node with isolated uid.
107    const int isolatedUid = 666;
108    std::vector<AttributionNodeInternal> attributions9 = {
109            CreateAttribution(isolatedUid, "GMSCoreModule3")};
110
111    std::vector<std::unique_ptr<LogEvent>> events;
112    // Events 1~4 are in the 1st bucket.
113    events.push_back(CreateAcquireWakelockEvent(
114        attributions1, "wl1", bucketStartTimeNs + 2));
115    events.push_back(CreateAcquireWakelockEvent(
116        attributions2, "wl1", bucketStartTimeNs + 200));
117    events.push_back(CreateAcquireWakelockEvent(
118        attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
119    events.push_back(CreateAcquireWakelockEvent(
120        attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
121
122    // Events 5~8 are in the 3rd bucket.
123    events.push_back(CreateAcquireWakelockEvent(
124        attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
125    events.push_back(CreateAcquireWakelockEvent(
126        attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
127    events.push_back(CreateAcquireWakelockEvent(
128        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
129    events.push_back(CreateAcquireWakelockEvent(
130        attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
131    events.push_back(CreateAcquireWakelockEvent(
132        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
133    events.push_back(CreateAcquireWakelockEvent(
134        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
135    events.push_back(CreateIsolatedUidChangedEvent(
136        isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
137    events.push_back(CreateIsolatedUidChangedEvent(
138        isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
139
140    sortLogEventsByTimestamp(&events);
141
142    for (const auto& event : events) {
143        processor->OnLogEvent(event.get());
144    }
145    ConfigMetricsReportList reports;
146    vector<uint8_t> buffer;
147    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
148                            &buffer);
149    EXPECT_TRUE(buffer.size() > 0);
150    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
151    backfillDimensionPath(&reports);
152    backfillStringInReport(&reports);
153    backfillStartEndTimestamp(&reports);
154    EXPECT_EQ(reports.reports_size(), 1);
155    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
156
157    StatsLogReport::CountMetricDataWrapper countMetrics;
158    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
159    EXPECT_EQ(countMetrics.data_size(), 4);
160
161    auto data = countMetrics.data(0);
162    ValidateAttributionUidAndTagDimension(
163        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 111,
164            "App1");
165    EXPECT_EQ(data.bucket_info_size(), 2);
166    EXPECT_EQ(data.bucket_info(0).count(), 2);
167    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
168    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
169    EXPECT_EQ(data.bucket_info(1).count(), 1);
170    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
171    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
172
173    data = countMetrics.data(1);
174    ValidateAttributionUidAndTagDimension(
175        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
176            "GMSCoreModule1");
177    EXPECT_EQ(data.bucket_info_size(), 2);
178    EXPECT_EQ(data.bucket_info(0).count(), 1);
179    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
180    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
181    EXPECT_EQ(data.bucket_info(1).count(), 1);
182    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
183    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
184
185    data = countMetrics.data(2);
186    ValidateAttributionUidAndTagDimension(
187        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
188            "GMSCoreModule3");
189    EXPECT_EQ(data.bucket_info_size(), 1);
190    EXPECT_EQ(data.bucket_info(0).count(), 1);
191    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
192    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
193
194    data = countMetrics.data(3);
195    ValidateAttributionUidAndTagDimension(
196        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 444,
197            "GMSCoreModule2");
198    EXPECT_EQ(data.bucket_info_size(), 1);
199    EXPECT_EQ(data.bucket_info(0).count(), 1);
200    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
201    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
202}
203
204TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
205    auto config = CreateStatsdConfig(Position::ALL);
206    int64_t bucketStartTimeNs = 10000000000;
207    int64_t bucketSizeNs =
208        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
209
210    ConfigKey cfgKey;
211    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
212    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
213    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
214
215    // Here it assumes that GMS core has two uids.
216    processor->getUidMap()->updateMap(
217            1, {222, 444, 111, 333}, {1, 1, 2, 2},
218            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
219             String16("APP3")});
220
221    // GMS core node is in the middle.
222    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
223                                                          CreateAttribution(222, "GMSCoreModule1"),
224                                                          CreateAttribution(333, "App3")};
225
226    // GMS core node is the last one.
227    std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
228                                                          CreateAttribution(333, "App3"),
229                                                          CreateAttribution(222, "GMSCoreModule1")};
230
231    // GMS core node is the first one.
232    std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
233                                                          CreateAttribution(333, "App3")};
234
235    // Single GMS core node.
236    std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
237
238    // GMS core has another uid.
239    std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
240                                                          CreateAttribution(444, "GMSCoreModule2"),
241                                                          CreateAttribution(333, "App3")};
242
243    // Multiple GMS core nodes.
244    std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
245                                                          CreateAttribution(222, "GMSCoreModule1")};
246
247    // No GMS core nodes.
248    std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
249                                                          CreateAttribution(333, "App3")};
250    std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
251
252    // GMS core node with isolated uid.
253    const int isolatedUid = 666;
254    std::vector<AttributionNodeInternal> attributions9 = {
255            CreateAttribution(isolatedUid, "GMSCoreModule1")};
256
257    std::vector<std::unique_ptr<LogEvent>> events;
258    // Events 1~4 are in the 1st bucket.
259    events.push_back(CreateAcquireWakelockEvent(
260        attributions1, "wl1", bucketStartTimeNs + 2));
261    events.push_back(CreateAcquireWakelockEvent(
262        attributions2, "wl1", bucketStartTimeNs + 200));
263    events.push_back(CreateAcquireWakelockEvent(
264        attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
265    events.push_back(CreateAcquireWakelockEvent(
266        attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
267
268    // Events 5~8 are in the 3rd bucket.
269    events.push_back(CreateAcquireWakelockEvent(
270        attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
271    events.push_back(CreateAcquireWakelockEvent(
272        attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
273    events.push_back(CreateAcquireWakelockEvent(
274        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
275    events.push_back(CreateAcquireWakelockEvent(
276        attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
277    events.push_back(CreateAcquireWakelockEvent(
278        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
279    events.push_back(CreateAcquireWakelockEvent(
280        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
281    events.push_back(CreateIsolatedUidChangedEvent(
282        isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
283    events.push_back(CreateIsolatedUidChangedEvent(
284        isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
285
286    sortLogEventsByTimestamp(&events);
287
288    for (const auto& event : events) {
289        processor->OnLogEvent(event.get());
290    }
291    ConfigMetricsReportList reports;
292    vector<uint8_t> buffer;
293    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
294                            &buffer);
295    EXPECT_TRUE(buffer.size() > 0);
296    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
297    backfillDimensionPath(&reports);
298    backfillStringInReport(&reports);
299    backfillStartEndTimestamp(&reports);
300    EXPECT_EQ(reports.reports_size(), 1);
301    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
302
303    StatsLogReport::CountMetricDataWrapper countMetrics;
304    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
305    EXPECT_EQ(countMetrics.data_size(), 6);
306
307    auto data = countMetrics.data(0);
308    ValidateAttributionUidAndTagDimension(
309        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
310    EXPECT_EQ(2, data.bucket_info_size());
311    EXPECT_EQ(1, data.bucket_info(0).count());
312    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
313              data.bucket_info(0).start_bucket_elapsed_nanos());
314    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
315              data.bucket_info(0).end_bucket_elapsed_nanos());
316    EXPECT_EQ(1, data.bucket_info(1).count());
317    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
318              data.bucket_info(1).start_bucket_elapsed_nanos());
319    EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs,
320              data.bucket_info(1).end_bucket_elapsed_nanos());
321
322    data = countMetrics.data(1);
323    ValidateUidDimension(
324        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
325    ValidateAttributionUidAndTagDimension(
326        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
327    ValidateUidDimension(
328        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
329    ValidateAttributionUidAndTagDimension(
330        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
331    EXPECT_EQ(data.bucket_info_size(), 1);
332    EXPECT_EQ(data.bucket_info(0).count(), 1);
333    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
334    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
335
336    data = countMetrics.data(2);
337    ValidateUidDimension(
338        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
339    ValidateAttributionUidAndTagDimension(
340        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
341    ValidateUidDimension(
342        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
343    ValidateAttributionUidAndTagDimension(
344        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
345    EXPECT_EQ(data.bucket_info_size(), 1);
346    EXPECT_EQ(data.bucket_info(0).count(), 1);
347    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
348              data.bucket_info(0).start_bucket_elapsed_nanos());
349    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
350              data.bucket_info(0).end_bucket_elapsed_nanos());
351
352    data = countMetrics.data(3);
353    ValidateUidDimension(
354        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
355    ValidateAttributionUidAndTagDimension(
356        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
357    ValidateUidDimension(
358        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
359    ValidateAttributionUidAndTagDimension(
360        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
361    ValidateUidDimension(
362        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
363    ValidateAttributionUidAndTagDimension(
364        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
365    EXPECT_EQ(data.bucket_info_size(), 1);
366    EXPECT_EQ(data.bucket_info(0).count(), 1);
367    EXPECT_EQ(bucketStartTimeNs,
368              data.bucket_info(0).start_bucket_elapsed_nanos());
369    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
370              data.bucket_info(0).end_bucket_elapsed_nanos());
371
372    data = countMetrics.data(4);
373    ValidateUidDimension(
374        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
375    ValidateAttributionUidAndTagDimension(
376        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
377    ValidateUidDimension(
378        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
379    ValidateAttributionUidAndTagDimension(
380        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
381    ValidateUidDimension(
382        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
383    ValidateAttributionUidAndTagDimension(
384        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
385    EXPECT_EQ(data.bucket_info_size(), 1);
386    EXPECT_EQ(data.bucket_info(0).count(), 1);
387    EXPECT_EQ(bucketStartTimeNs,
388              data.bucket_info(0).start_bucket_elapsed_nanos());
389    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
390              data.bucket_info(0).end_bucket_elapsed_nanos());
391
392    data = countMetrics.data(5);
393    ValidateUidDimension(
394        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
395    ValidateAttributionUidAndTagDimension(
396        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
397    ValidateUidDimension(
398        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
399    ValidateAttributionUidAndTagDimension(
400        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
401    ValidateUidDimension(
402        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
403    ValidateAttributionUidAndTagDimension(
404        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
405    EXPECT_EQ(data.bucket_info_size(), 1);
406    EXPECT_EQ(data.bucket_info(0).count(), 1);
407    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
408              data.bucket_info(0).start_bucket_elapsed_nanos());
409    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
410              data.bucket_info(0).end_bucket_elapsed_nanos());
411}
412
413#else
414GTEST_LOG_(INFO) << "This test does nothing.\n";
415#endif
416
417}  // namespace statsd
418}  // namespace os
419}  // namespace android
420