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 "StatsService.h" 16 17 #include <android/binder_interface_utils.h> 18 #include <gmock/gmock.h> 19 #include <gtest/gtest.h> 20 #include <stdio.h> 21 22 #include "config/ConfigKey.h" 23 #include "packages/UidMap.h" 24 #include "src/statsd_config.pb.h" 25 #include "tests/statsd_test_util.h" 26 27 using namespace android; 28 using namespace testing; 29 30 namespace android { 31 namespace os { 32 namespace statsd { 33 34 using android::util::ProtoOutputStream; 35 using ::ndk::SharedRefBase; 36 37 #ifdef __ANDROID__ 38 39 namespace { 40 41 const int64_t metricId = 123456; 42 const int32_t ATOM_TAG = util::SUBSYSTEM_SLEEP_STATE; 43 CreateStatsdConfig(const GaugeMetric::SamplingType samplingType)44 StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType samplingType) { 45 StatsdConfig config; 46 config.add_default_pull_packages("AID_ROOT"); // Fake puller is registered with root. 47 auto atomMatcher = CreateSimpleAtomMatcher("TestMatcher", ATOM_TAG); 48 *config.add_atom_matcher() = atomMatcher; 49 *config.add_gauge_metric() = 50 createGaugeMetric("GAUGE1", atomMatcher.id(), samplingType, nullopt, nullopt); 51 config.set_hash_strings_in_metric_report(false); 52 return config; 53 } 54 55 class FakeSubsystemSleepCallbackWithTiming : public FakeSubsystemSleepCallback { 56 public: onPullAtom(int atomTag,const shared_ptr<IPullAtomResultReceiver> & resultReceiver)57 Status onPullAtom(int atomTag, 58 const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override { 59 mPullTimeNs = getElapsedRealtimeNs(); 60 return FakeSubsystemSleepCallback::onPullAtom(atomTag, resultReceiver); 61 } 62 int64_t mPullTimeNs = 0; 63 }; 64 65 } // namespace 66 TEST(StatsServiceTest,TestAddConfig_simple)67 TEST(StatsServiceTest, TestAddConfig_simple) { 68 const sp<UidMap> uidMap = new UidMap(); 69 shared_ptr<StatsService> service = SharedRefBase::make<StatsService>( 70 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>()); 71 const int kConfigKey = 12345; 72 const int kCallingUid = 123; 73 StatsdConfig config; 74 config.set_id(kConfigKey); 75 string serialized = config.SerializeAsString(); 76 77 EXPECT_TRUE(service->addConfigurationChecked(kCallingUid, kConfigKey, 78 {serialized.begin(), serialized.end()})); 79 service->removeConfiguration(kConfigKey, kCallingUid); 80 ConfigKey configKey(kCallingUid, kConfigKey); 81 service->mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), 82 false /* include_current_bucket*/, true /* erase_data */, 83 ADB_DUMP, NO_TIME_CONSTRAINTS, nullptr); 84 } 85 TEST(StatsServiceTest,TestAddConfig_empty)86 TEST(StatsServiceTest, TestAddConfig_empty) { 87 const sp<UidMap> uidMap = new UidMap(); 88 shared_ptr<StatsService> service = SharedRefBase::make<StatsService>( 89 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>()); 90 string serialized = ""; 91 const int kConfigKey = 12345; 92 const int kCallingUid = 123; 93 EXPECT_TRUE(service->addConfigurationChecked(kCallingUid, kConfigKey, 94 {serialized.begin(), serialized.end()})); 95 service->removeConfiguration(kConfigKey, kCallingUid); 96 ConfigKey configKey(kCallingUid, kConfigKey); 97 service->mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), 98 false /* include_current_bucket*/, true /* erase_data */, 99 ADB_DUMP, NO_TIME_CONSTRAINTS, nullptr); 100 } 101 TEST(StatsServiceTest,TestAddConfig_invalid)102 TEST(StatsServiceTest, TestAddConfig_invalid) { 103 const sp<UidMap> uidMap = new UidMap(); 104 shared_ptr<StatsService> service = SharedRefBase::make<StatsService>( 105 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>()); 106 string serialized = "Invalid config!"; 107 108 EXPECT_FALSE( 109 service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()})); 110 } 111 TEST(StatsServiceTest,TestGetUidFromArgs)112 TEST(StatsServiceTest, TestGetUidFromArgs) { 113 Vector<String8> args; 114 args.push(String8("-1")); 115 args.push(String8("0")); 116 args.push(String8("1")); 117 args.push(String8("a1")); 118 args.push(String8("")); 119 120 int32_t uid; 121 122 const sp<UidMap> uidMap = new UidMap(); 123 shared_ptr<StatsService> service = SharedRefBase::make<StatsService>( 124 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>()); 125 service->mEngBuild = true; 126 127 // "-1" 128 EXPECT_FALSE(service->getUidFromArgs(args, 0, uid)); 129 130 // "0" 131 EXPECT_TRUE(service->getUidFromArgs(args, 1, uid)); 132 EXPECT_EQ(0, uid); 133 134 // "1" 135 EXPECT_TRUE(service->getUidFromArgs(args, 2, uid)); 136 EXPECT_EQ(1, uid); 137 138 // "a1" 139 EXPECT_FALSE(service->getUidFromArgs(args, 3, uid)); 140 141 // "" 142 EXPECT_FALSE(service->getUidFromArgs(args, 4, uid)); 143 144 // For a non-userdebug, uid "1" cannot be impersonated. 145 service->mEngBuild = false; 146 EXPECT_FALSE(service->getUidFromArgs(args, 2, uid)); 147 } 148 TEST_F(StatsServiceConfigTest,StatsServiceStatsdInitTest)149 TEST_F(StatsServiceConfigTest, StatsServiceStatsdInitTest) { 150 // used for error threshold tolerance due to sleep() is involved 151 const int64_t ERROR_THRESHOLD_NS = 25 * 1000000; // 25 ms 152 const int INIT_DELAY_SEC = 3; 153 154 auto pullAtomCallback = SharedRefBase::make<FakeSubsystemSleepCallbackWithTiming>(); 155 156 // TODO: evaluate to use service->registerNativePullAtomCallback() API 157 service->mPullerManager->RegisterPullAtomCallback(/*uid=*/0, ATOM_TAG, NS_PER_SEC, 158 NS_PER_SEC * 10, {}, pullAtomCallback); 159 160 StatsdConfig config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE); 161 config.set_id(kConfigKey); 162 const int64_t createConfigTimeNs = getElapsedRealtimeNs(); 163 ASSERT_TRUE(sendConfig(config)); 164 ASSERT_EQ(2, pullAtomCallback->pullNum); 165 166 service->mProcessor->mPullerManager->ForceClearPullerCache(); 167 168 const int64_t initCompletedTimeNs = getElapsedRealtimeNs(); 169 service->onStatsdInitCompleted(INIT_DELAY_SEC); 170 ASSERT_EQ(3, pullAtomCallback->pullNum); 171 172 // Checking pull with or without delay according to the flag value 173 const int64_t lastPullNs = pullAtomCallback->mPullTimeNs; 174 175 EXPECT_GE(lastPullNs, initCompletedTimeNs + INIT_DELAY_SEC * NS_PER_SEC); 176 EXPECT_LE(lastPullNs, initCompletedTimeNs + INIT_DELAY_SEC * NS_PER_SEC + ERROR_THRESHOLD_NS); 177 178 const int64_t bucketSizeNs = 179 TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000; 180 const int64_t dumpReportTsNanos = createConfigTimeNs + bucketSizeNs + NS_PER_SEC; 181 182 vector<uint8_t> output; 183 ConfigKey configKey(kCallingUid, kConfigKey); 184 service->mProcessor->onDumpReport(configKey, dumpReportTsNanos, 185 /*include_current_bucket=*/false, /*erase_data=*/true, 186 ADB_DUMP, FAST, &output); 187 ConfigMetricsReportList reports; 188 reports.ParseFromArray(output.data(), output.size()); 189 ASSERT_EQ(1, reports.reports_size()); 190 191 backfillDimensionPath(&reports); 192 backfillStartEndTimestamp(&reports); 193 backfillAggregatedAtoms(&reports); 194 StatsLogReport::GaugeMetricDataWrapper gaugeMetrics = 195 reports.reports(0).metrics(0).gauge_metrics(); 196 ASSERT_EQ(gaugeMetrics.skipped_size(), 0); 197 ASSERT_GT((int)gaugeMetrics.data_size(), 0); 198 const auto data = gaugeMetrics.data(0); 199 ASSERT_EQ(2, data.bucket_info_size()); 200 201 const auto bucketInfo0 = data.bucket_info(0); 202 const auto bucketInfo1 = data.bucket_info(1); 203 204 EXPECT_GE(NanoToMillis(bucketInfo0.start_bucket_elapsed_nanos()), 205 NanoToMillis(createConfigTimeNs)); 206 EXPECT_LE(NanoToMillis(bucketInfo0.start_bucket_elapsed_nanos()), 207 NanoToMillis(createConfigTimeNs + ERROR_THRESHOLD_NS)); 208 209 EXPECT_EQ(NanoToMillis(bucketInfo0.end_bucket_elapsed_nanos()), 210 NanoToMillis(bucketInfo1.start_bucket_elapsed_nanos())); 211 212 ASSERT_EQ(1, bucketInfo1.atom_size()); 213 ASSERT_GT(bucketInfo1.atom(0).subsystem_sleep_state().time_millis(), 0); 214 215 EXPECT_GE(NanoToMillis(bucketInfo1.start_bucket_elapsed_nanos()), 216 NanoToMillis(initCompletedTimeNs + INIT_DELAY_SEC * NS_PER_SEC)); 217 EXPECT_LE(NanoToMillis(bucketInfo1.start_bucket_elapsed_nanos()), 218 NanoToMillis(initCompletedTimeNs + INIT_DELAY_SEC * NS_PER_SEC + ERROR_THRESHOLD_NS)); 219 220 // this check confirms that bucket end is not affected by the StatsService init delay 221 EXPECT_EQ(NanoToMillis(bucketInfo1.end_bucket_elapsed_nanos()), 222 NanoToMillis(service->mProcessor->mTimeBaseNs + bucketSizeNs)); 223 } 224 225 #else 226 GTEST_LOG_(INFO) << "This test does nothing.\n"; 227 #endif 228 229 } // namespace statsd 230 } // namespace os 231 } // namespace android 232