Home | History | Annotate | Download | only in metrics
      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 "src/metrics/CountMetricProducer.h"
     16 #include "src/stats_log_util.h"
     17 #include "metrics_test_helper.h"
     18 #include "tests/statsd_test_util.h"
     19 
     20 #include <gmock/gmock.h>
     21 #include <gtest/gtest.h>
     22 #include <math.h>
     23 #include <stdio.h>
     24 #include <vector>
     25 
     26 using namespace testing;
     27 using android::sp;
     28 using std::set;
     29 using std::unordered_map;
     30 using std::vector;
     31 
     32 #ifdef __ANDROID__
     33 
     34 namespace android {
     35 namespace os {
     36 namespace statsd {
     37 
     38 const ConfigKey kConfigKey(0, 12345);
     39 
     40 TEST(CountMetricProducerTest, TestFirstBucket) {
     41     CountMetric metric;
     42     metric.set_id(1);
     43     metric.set_bucket(ONE_MINUTE);
     44     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     45 
     46     CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
     47                                       5, 600 * NS_PER_SEC + NS_PER_SEC/2);
     48     EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
     49     EXPECT_EQ(10, countProducer.mCurrentBucketNum);
     50     EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
     51 }
     52 
     53 TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
     54     int64_t bucketStartTimeNs = 10000000000;
     55     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
     56     int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
     57     int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
     58     int tagId = 1;
     59 
     60     CountMetric metric;
     61     metric.set_id(1);
     62     metric.set_bucket(ONE_MINUTE);
     63 
     64     LogEvent event1(tagId, bucketStartTimeNs + 1);
     65     event1.init();
     66     LogEvent event2(tagId, bucketStartTimeNs + 2);
     67     event2.init();
     68 
     69     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     70 
     71     CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
     72                                       bucketStartTimeNs, bucketStartTimeNs);
     73 
     74     // 2 events in bucket 1.
     75     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
     76     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
     77 
     78     // Flushes at event #2.
     79     countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
     80     EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
     81 
     82     // Flushes.
     83     countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
     84     EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
     85     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
     86                 countProducer.mPastBuckets.end());
     87     const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
     88     EXPECT_EQ(1UL, buckets.size());
     89     EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
     90     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
     91     EXPECT_EQ(2LL, buckets[0].mCount);
     92 
     93     // 1 matched event happens in bucket 2.
     94     LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
     95     event3.init();
     96 
     97     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
     98     countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
     99     EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
    100     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
    101                 countProducer.mPastBuckets.end());
    102     EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    103     const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
    104     EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
    105     EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
    106     EXPECT_EQ(1LL, bucketInfo2.mCount);
    107 
    108     // nothing happens in bucket 3. we should not record anything for bucket 3.
    109     countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
    110     EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
    111     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
    112                 countProducer.mPastBuckets.end());
    113     const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    114     EXPECT_EQ(2UL, buckets3.size());
    115 }
    116 
    117 TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
    118     int64_t bucketStartTimeNs = 10000000000;
    119     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    120 
    121     CountMetric metric;
    122     metric.set_id(1);
    123     metric.set_bucket(ONE_MINUTE);
    124     metric.set_condition(StringToId("SCREEN_ON"));
    125 
    126     LogEvent event1(1, bucketStartTimeNs + 1);
    127     event1.init();
    128 
    129     LogEvent event2(1, bucketStartTimeNs + 10);
    130     event2.init();
    131 
    132     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    133 
    134     CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs, bucketStartTimeNs);
    135 
    136     countProducer.onConditionChanged(true, bucketStartTimeNs);
    137     countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
    138     EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
    139 
    140     countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
    141     // Upon this match event, the matched event1 is flushed.
    142     countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
    143     EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
    144 
    145     countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
    146     EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
    147     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
    148                 countProducer.mPastBuckets.end());
    149     {
    150         const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    151         EXPECT_EQ(1UL, buckets.size());
    152         const auto& bucketInfo = buckets[0];
    153         EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
    154         EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
    155         EXPECT_EQ(1LL, bucketInfo.mCount);
    156     }
    157 }
    158 
    159 TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
    160     int64_t bucketStartTimeNs = 10000000000;
    161     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    162 
    163     int tagId = 1;
    164     int conditionTagId = 2;
    165 
    166     CountMetric metric;
    167     metric.set_id(1);
    168     metric.set_bucket(ONE_MINUTE);
    169     metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
    170     MetricConditionLink* link = metric.add_links();
    171     link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
    172     buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
    173     buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
    174 
    175     LogEvent event1(tagId, bucketStartTimeNs + 1);
    176     event1.write("111");  // uid
    177     event1.init();
    178     ConditionKey key1;
    179     key1[StringToId("APP_IN_BACKGROUND_PER_UID")] =
    180         {getMockedDimensionKey(conditionTagId, 2, "111")};
    181 
    182     LogEvent event2(tagId, bucketStartTimeNs + 10);
    183     event2.write("222");  // uid
    184     event2.init();
    185     ConditionKey key2;
    186     key2[StringToId("APP_IN_BACKGROUND_PER_UID")] =
    187         {getMockedDimensionKey(conditionTagId, 2, "222")};
    188 
    189     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    190     EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse));
    191 
    192     EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue));
    193 
    194     CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
    195                                       bucketStartTimeNs, bucketStartTimeNs);
    196 
    197     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
    198     countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
    199     EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
    200 
    201     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
    202     countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
    203     EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
    204     EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
    205                 countProducer.mPastBuckets.end());
    206     const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
    207     EXPECT_EQ(1UL, buckets.size());
    208     const auto& bucketInfo = buckets[0];
    209     EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
    210     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
    211     EXPECT_EQ(1LL, bucketInfo.mCount);
    212 }
    213 
    214 TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
    215     sp<AlarmMonitor> alarmMonitor;
    216     int64_t bucketStartTimeNs = 10000000000;
    217     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    218     int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
    219 
    220     int tagId = 1;
    221     int conditionTagId = 2;
    222 
    223     CountMetric metric;
    224     metric.set_id(1);
    225     metric.set_bucket(ONE_MINUTE);
    226     Alert alert;
    227     alert.set_num_buckets(3);
    228     alert.set_trigger_if_sum_gt(2);
    229     LogEvent event1(tagId, bucketStartTimeNs + 1);
    230     event1.write("111");  // uid
    231     event1.init();
    232     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    233     CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
    234                                       bucketStartTimeNs, bucketStartTimeNs);
    235 
    236     sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
    237     EXPECT_TRUE(anomalyTracker != nullptr);
    238 
    239     // Bucket is flushed yet.
    240     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
    241     EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
    242     EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
    243 
    244     // App upgrade forces bucket flush.
    245     // Check that there's a past bucket and the bucket end is not adjusted.
    246     countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
    247     EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    248     EXPECT_EQ((long long)bucketStartTimeNs,
    249               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
    250     EXPECT_EQ((long long)eventUpgradeTimeNs,
    251               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
    252     EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
    253     // Anomaly tracker only contains full buckets.
    254     EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
    255 
    256     int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
    257     // Next event occurs in same bucket as partial bucket created.
    258     LogEvent event2(tagId, bucketStartTimeNs + 59 * NS_PER_SEC + 10);
    259     event2.write("222");  // uid
    260     event2.init();
    261     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
    262     EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    263     EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
    264     EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
    265 
    266     // Third event in following bucket.
    267     LogEvent event3(tagId, bucketStartTimeNs + 62 * NS_PER_SEC + 10);
    268     event3.write("333");  // uid
    269     event3.init();
    270     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
    271     EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    272     EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
    273     EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
    274 }
    275 
    276 TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
    277     int64_t bucketStartTimeNs = 10000000000;
    278     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    279     int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
    280 
    281     int tagId = 1;
    282     int conditionTagId = 2;
    283 
    284     CountMetric metric;
    285     metric.set_id(1);
    286     metric.set_bucket(ONE_MINUTE);
    287     LogEvent event1(tagId, bucketStartTimeNs + 1);
    288     event1.write("111");  // uid
    289     event1.init();
    290     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    291     CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
    292                                       bucketStartTimeNs, bucketStartTimeNs);
    293 
    294     // Bucket is flushed yet.
    295     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
    296     EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
    297 
    298     // App upgrade forces bucket flush.
    299     // Check that there's a past bucket and the bucket end is not adjusted.
    300     countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
    301     EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    302     EXPECT_EQ((int64_t)bucketStartTimeNs,
    303               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
    304     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
    305               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
    306     EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
    307 
    308     // Next event occurs in same bucket as partial bucket created.
    309     LogEvent event2(tagId, bucketStartTimeNs + 70 * NS_PER_SEC + 10);
    310     event2.write("222");  // uid
    311     event2.init();
    312     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
    313     EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    314 
    315     // Third event in following bucket.
    316     LogEvent event3(tagId, bucketStartTimeNs + 121 * NS_PER_SEC + 10);
    317     event3.write("333");  // uid
    318     event3.init();
    319     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
    320     EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
    321     EXPECT_EQ((int64_t)eventUpgradeTimeNs,
    322               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
    323     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
    324               countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
    325 }
    326 
    327 TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
    328     sp<AlarmMonitor> alarmMonitor;
    329     Alert alert;
    330     alert.set_id(11);
    331     alert.set_metric_id(1);
    332     alert.set_trigger_if_sum_gt(2);
    333     alert.set_num_buckets(2);
    334     const int32_t refPeriodSec = 1;
    335     alert.set_refractory_period_secs(refPeriodSec);
    336 
    337     int64_t bucketStartTimeNs = 10000000000;
    338     int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
    339     int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
    340     int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
    341 
    342     CountMetric metric;
    343     metric.set_id(1);
    344     metric.set_bucket(ONE_MINUTE);
    345 
    346     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
    347     CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
    348                                       bucketStartTimeNs, bucketStartTimeNs);
    349 
    350     sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
    351 
    352     int tagId = 1;
    353     LogEvent event1(tagId, bucketStartTimeNs + 1);
    354     event1.init();
    355     LogEvent event2(tagId, bucketStartTimeNs + 2);
    356     event2.init();
    357     LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
    358     event3.init();
    359     LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
    360     event4.init();
    361     LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
    362     event5.init();
    363     LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
    364     event6.init();
    365     LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
    366     event7.init();
    367 
    368     // Two events in bucket #0.
    369     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
    370     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
    371 
    372     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
    373     EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
    374     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
    375 
    376     // One event in bucket #2. No alarm as bucket #0 is trashed out.
    377     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
    378     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
    379     EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
    380     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
    381 
    382     // Two events in bucket #3.
    383     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
    384     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
    385     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
    386     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
    387     EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
    388     // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
    389     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
    390             std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
    391 
    392     countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
    393     EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
    394     EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
    395     EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
    396             std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
    397 }
    398 
    399 }  // namespace statsd
    400 }  // namespace os
    401 }  // namespace android
    402 #else
    403 GTEST_LOG_(INFO) << "This test does nothing.\n";
    404 #endif
    405