Home | History | Annotate | Download | only in e2e
      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 <binder/IPCThreadState.h>
     18 #include "src/StatsLogProcessor.h"
     19 #include "src/StatsService.h"
     20 #include "src/stats_log_util.h"
     21 #include "tests/statsd_test_util.h"
     22 
     23 #include <vector>
     24 
     25 namespace android {
     26 namespace os {
     27 namespace statsd {
     28 
     29 #ifdef __ANDROID__
     30 
     31 const string kAndroid = "android";
     32 const string kApp1 = "app1.sharing.1";
     33 const int kConfigKey = 789130123;  // Randomly chosen to avoid collisions with existing configs.
     34 
     35 void SendConfig(StatsService& service, const StatsdConfig& config) {
     36     string str;
     37     config.SerializeToString(&str);
     38     std::vector<uint8_t> configAsVec(str.begin(), str.end());
     39     bool success;
     40     service.addConfiguration(kConfigKey, configAsVec, String16(kAndroid.c_str()));
     41 }
     42 
     43 ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
     44                                bool include_current = false) {
     45     vector<uint8_t> output;
     46     IPCThreadState* ipc = IPCThreadState::self();
     47     ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
     48     processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
     49                             true /* erase_data */, ADB_DUMP, NO_TIME_CONSTRAINTS, &output);
     50     ConfigMetricsReportList reports;
     51     reports.ParseFromArray(output.data(), output.size());
     52     EXPECT_EQ(1, reports.reports_size());
     53     return reports.reports(0);
     54 }
     55 
     56 StatsdConfig MakeConfig() {
     57     StatsdConfig config;
     58     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
     59 
     60     auto appCrashMatcher = CreateProcessCrashAtomMatcher();
     61     *config.add_atom_matcher() = appCrashMatcher;
     62     auto countMetric = config.add_count_metric();
     63     countMetric->set_id(StringToId("AppCrashes"));
     64     countMetric->set_what(appCrashMatcher.id());
     65     countMetric->set_bucket(FIVE_MINUTES);
     66     return config;
     67 }
     68 
     69 StatsdConfig MakeValueMetricConfig(int64_t minTime) {
     70     StatsdConfig config;
     71     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
     72 
     73     auto pulledAtomMatcher =
     74             CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
     75     *config.add_atom_matcher() = pulledAtomMatcher;
     76     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
     77     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
     78 
     79     auto valueMetric = config.add_value_metric();
     80     valueMetric->set_id(123456);
     81     valueMetric->set_what(pulledAtomMatcher.id());
     82     *valueMetric->mutable_value_field() =
     83             CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
     84     *valueMetric->mutable_dimensions_in_what() =
     85             CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
     86     valueMetric->set_bucket(FIVE_MINUTES);
     87     valueMetric->set_min_bucket_size_nanos(minTime);
     88     valueMetric->set_use_absolute_value_on_reset(true);
     89     return config;
     90 }
     91 
     92 StatsdConfig MakeGaugeMetricConfig(int64_t minTime) {
     93     StatsdConfig config;
     94     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
     95 
     96     auto pulledAtomMatcher =
     97                 CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
     98     *config.add_atom_matcher() = pulledAtomMatcher;
     99     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
    100     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
    101 
    102     auto gaugeMetric = config.add_gauge_metric();
    103     gaugeMetric->set_id(123456);
    104     gaugeMetric->set_what(pulledAtomMatcher.id());
    105     gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
    106     *gaugeMetric->mutable_dimensions_in_what() =
    107             CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
    108     gaugeMetric->set_bucket(FIVE_MINUTES);
    109     gaugeMetric->set_min_bucket_size_nanos(minTime);
    110     return config;
    111 }
    112 
    113 TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
    114     StatsService service(nullptr, nullptr);
    115     SendConfig(service, MakeConfig());
    116     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    117                                              // initialized with.
    118 
    119     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    120     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
    121 
    122     ConfigMetricsReport report = GetReports(service.mProcessor, start + 3);
    123     // Expect no metrics since the bucket has not finished yet.
    124     EXPECT_EQ(1, report.metrics_size());
    125     EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
    126 }
    127 
    128 TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
    129     StatsService service(nullptr, nullptr);
    130     SendConfig(service, MakeConfig());
    131     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    132                                              // initialized with.
    133 
    134     // Force the uidmap to update at timestamp 2.
    135     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    136     // This is a new installation, so there shouldn't be a split (should be same as the without
    137     // split case).
    138     service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
    139                                String16(""));
    140     // Goes into the second bucket.
    141     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
    142 
    143     ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
    144     EXPECT_EQ(1, report.metrics_size());
    145     EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
    146 }
    147 
    148 TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
    149     StatsService service(nullptr, nullptr);
    150     SendConfig(service, MakeConfig());
    151     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    152                                              // initialized with.
    153     service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
    154                                {String16("")});
    155 
    156     // Force the uidmap to update at timestamp 2.
    157     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    158     service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
    159                                String16(""));
    160     // Goes into the second bucket.
    161     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
    162 
    163     ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
    164     backfillStartEndTimestamp(&report);
    165     EXPECT_EQ(1, report.metrics_size());
    166     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    167                     has_start_bucket_elapsed_nanos());
    168     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    169                     has_end_bucket_elapsed_nanos());
    170     EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
    171 }
    172 
    173 TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
    174     StatsService service(nullptr, nullptr);
    175     SendConfig(service, MakeConfig());
    176     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    177                                              // initialized with.
    178     service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
    179                                {String16("")});
    180 
    181     // Force the uidmap to update at timestamp 2.
    182     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    183     service.mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
    184     // Goes into the second bucket.
    185     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
    186 
    187     ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
    188     backfillStartEndTimestamp(&report);
    189     EXPECT_EQ(1, report.metrics_size());
    190     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    191                     has_start_bucket_elapsed_nanos());
    192     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    193                     has_end_bucket_elapsed_nanos());
    194     EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
    195 }
    196 
    197 TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
    198     StatsService service(nullptr, nullptr);
    199     // Partial buckets don't occur when app is first installed.
    200     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
    201     SendConfig(service, MakeValueMetricConfig(0));
    202     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    203                                              // initialized with.
    204 
    205     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    206     service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
    207                                String16("v2"), String16(""));
    208 
    209     ConfigMetricsReport report =
    210             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
    211     EXPECT_EQ(1, report.metrics_size());
    212     EXPECT_EQ(0, report.metrics(0).value_metrics().skipped_size());
    213 }
    214 
    215 TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
    216     StatsService service(nullptr, nullptr);
    217     // Partial buckets don't occur when app is first installed.
    218     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
    219     SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
    220     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    221                                              // initialized with.
    222 
    223     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
    224     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    225     service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
    226                                String16(""));
    227 
    228     ConfigMetricsReport report =
    229             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
    230     backfillStartEndTimestamp(&report);
    231     EXPECT_EQ(1, report.metrics_size());
    232     EXPECT_EQ(1, report.metrics(0).value_metrics().skipped_size());
    233     EXPECT_TRUE(report.metrics(0).value_metrics().skipped(0).has_start_bucket_elapsed_nanos());
    234     // Can't test the start time since it will be based on the actual time when the pulling occurs.
    235     EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
    236               report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
    237 }
    238 
    239 TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
    240     StatsService service(nullptr, nullptr);
    241     // Partial buckets don't occur when app is first installed.
    242     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
    243     SendConfig(service, MakeGaugeMetricConfig(0));
    244     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    245                                              // initialized with.
    246 
    247     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    248     service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
    249                                String16("v2"), String16(""));
    250 
    251     ConfigMetricsReport report =
    252             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
    253     EXPECT_EQ(1, report.metrics_size());
    254     EXPECT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
    255 }
    256 
    257 TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
    258     StatsService service(nullptr, nullptr);
    259     // Partial buckets don't occur when app is first installed.
    260     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
    261     SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
    262     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    263                                              // initialized with.
    264 
    265     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
    266     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    267     service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
    268                                String16(""));
    269 
    270     ConfigMetricsReport report =
    271             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
    272     backfillStartEndTimestamp(&report);
    273     EXPECT_EQ(1, report.metrics_size());
    274     EXPECT_EQ(1, report.metrics(0).gauge_metrics().skipped_size());
    275     // Can't test the start time since it will be based on the actual time when the pulling occurs.
    276     EXPECT_TRUE(report.metrics(0).gauge_metrics().skipped(0).has_start_bucket_elapsed_nanos());
    277     EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
    278               report.metrics(0).gauge_metrics().skipped(0).end_bucket_elapsed_nanos());
    279 }
    280 
    281 #else
    282 GTEST_LOG_(INFO) << "This test does nothing.\n";
    283 #endif
    284 
    285 }  // namespace statsd
    286 }  // namespace os
    287 }  // namespace android
    288