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                             ADB_DUMP, &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 temperatureAtomMatcher = CreateTemperatureAtomMatcher();
     74     *config.add_atom_matcher() = temperatureAtomMatcher;
     75     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
     76     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
     77 
     78     auto valueMetric = config.add_value_metric();
     79     valueMetric->set_id(123456);
     80     valueMetric->set_what(temperatureAtomMatcher.id());
     81     *valueMetric->mutable_value_field() =
     82             CreateDimensions(android::util::TEMPERATURE, {3 /* temperature degree field */});
     83     *valueMetric->mutable_dimensions_in_what() =
     84             CreateDimensions(android::util::TEMPERATURE, {2 /* sensor name field */});
     85     valueMetric->set_bucket(FIVE_MINUTES);
     86     valueMetric->set_min_bucket_size_nanos(minTime);
     87     valueMetric->set_use_absolute_value_on_reset(true);
     88     return config;
     89 }
     90 
     91 StatsdConfig MakeGaugeMetricConfig(int64_t minTime) {
     92     StatsdConfig config;
     93     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
     94 
     95     auto temperatureAtomMatcher = CreateTemperatureAtomMatcher();
     96     *config.add_atom_matcher() = temperatureAtomMatcher;
     97     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
     98     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
     99 
    100     auto gaugeMetric = config.add_gauge_metric();
    101     gaugeMetric->set_id(123456);
    102     gaugeMetric->set_what(temperatureAtomMatcher.id());
    103     gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
    104     *gaugeMetric->mutable_dimensions_in_what() =
    105             CreateDimensions(android::util::TEMPERATURE, {2 /* sensor name field */});
    106     gaugeMetric->set_bucket(FIVE_MINUTES);
    107     gaugeMetric->set_min_bucket_size_nanos(minTime);
    108     return config;
    109 }
    110 
    111 TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
    112     StatsService service(nullptr);
    113     SendConfig(service, MakeConfig());
    114     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    115                                              // initialized with.
    116 
    117     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    118     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
    119 
    120     ConfigMetricsReport report = GetReports(service.mProcessor, start + 3);
    121     // Expect no metrics since the bucket has not finished yet.
    122     EXPECT_EQ(0, report.metrics_size());
    123 }
    124 
    125 TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
    126     StatsService service(nullptr);
    127     SendConfig(service, MakeConfig());
    128     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    129                                              // initialized with.
    130 
    131     // Force the uidmap to update at timestamp 2.
    132     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    133     // This is a new installation, so there shouldn't be a split (should be same as the without
    134     // split case).
    135     service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
    136     // Goes into the second bucket.
    137     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
    138 
    139     ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
    140     EXPECT_EQ(0, report.metrics_size());
    141 }
    142 
    143 TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
    144     StatsService service(nullptr);
    145     SendConfig(service, MakeConfig());
    146     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    147                                              // initialized with.
    148     service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
    149 
    150     // Force the uidmap to update at timestamp 2.
    151     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    152     service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
    153     // Goes into the second bucket.
    154     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
    155 
    156     ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
    157     backfillStartEndTimestamp(&report);
    158     EXPECT_EQ(1, report.metrics_size());
    159     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    160                     has_start_bucket_elapsed_nanos());
    161     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    162                     has_end_bucket_elapsed_nanos());
    163     EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
    164 }
    165 
    166 TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
    167     StatsService service(nullptr);
    168     SendConfig(service, MakeConfig());
    169     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    170                                              // initialized with.
    171     service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
    172 
    173     // Force the uidmap to update at timestamp 2.
    174     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
    175     service.mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
    176     // Goes into the second bucket.
    177     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
    178 
    179     ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
    180     backfillStartEndTimestamp(&report);
    181     EXPECT_EQ(1, report.metrics_size());
    182     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    183                     has_start_bucket_elapsed_nanos());
    184     EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
    185                     has_end_bucket_elapsed_nanos());
    186     EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
    187 }
    188 
    189 TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
    190     StatsService service(nullptr);
    191     // Partial buckets don't occur when app is first installed.
    192     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
    193     SendConfig(service, MakeValueMetricConfig(0));
    194     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    195                                              // initialized with.
    196 
    197     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    198     service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
    199 
    200     ConfigMetricsReport report =
    201             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
    202     EXPECT_EQ(1, report.metrics_size());
    203     EXPECT_EQ(0, report.metrics(0).value_metrics().skipped_size());
    204 }
    205 
    206 TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
    207     StatsService service(nullptr);
    208     // Partial buckets don't occur when app is first installed.
    209     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
    210     SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
    211     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    212                                              // initialized with.
    213 
    214     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
    215     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    216     service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2);
    217 
    218     ConfigMetricsReport report =
    219             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
    220     backfillStartEndTimestamp(&report);
    221     EXPECT_EQ(1, report.metrics_size());
    222     EXPECT_EQ(1, report.metrics(0).value_metrics().skipped_size());
    223     EXPECT_TRUE(report.metrics(0).value_metrics().skipped(0).has_start_bucket_elapsed_nanos());
    224     // Can't test the start time since it will be based on the actual time when the pulling occurs.
    225     EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
    226               report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
    227 }
    228 
    229 TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
    230     StatsService service(nullptr);
    231     // Partial buckets don't occur when app is first installed.
    232     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
    233     SendConfig(service, MakeGaugeMetricConfig(0));
    234     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    235                                              // initialized with.
    236 
    237     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    238     service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
    239 
    240     ConfigMetricsReport report =
    241             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
    242     EXPECT_EQ(1, report.metrics_size());
    243     EXPECT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
    244 }
    245 
    246 TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
    247     StatsService service(nullptr);
    248     // Partial buckets don't occur when app is first installed.
    249     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
    250     SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
    251     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
    252                                              // initialized with.
    253 
    254     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
    255     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
    256     service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2);
    257 
    258     ConfigMetricsReport report =
    259             GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
    260     backfillStartEndTimestamp(&report);
    261     EXPECT_EQ(1, report.metrics_size());
    262     EXPECT_EQ(1, report.metrics(0).gauge_metrics().skipped_size());
    263     // Can't test the start time since it will be based on the actual time when the pulling occurs.
    264     EXPECT_TRUE(report.metrics(0).gauge_metrics().skipped(0).has_start_bucket_elapsed_nanos());
    265     EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
    266               report.metrics(0).gauge_metrics().skipped(0).end_bucket_elapsed_nanos());
    267 }
    268 
    269 #else
    270 GTEST_LOG_(INFO) << "This test does nothing.\n";
    271 #endif
    272 
    273 }  // namespace statsd
    274 }  // namespace os
    275 }  // namespace android
    276