• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::modules::sdklevel::IsAtLeastU;
35 using android::util::ProtoOutputStream;
36 using ::ndk::SharedRefBase;
37 
38 #ifdef __ANDROID__
39 
40 namespace {
41 
42 const int64_t metricId = 123456;
43 const int32_t ATOM_TAG = util::SUBSYSTEM_SLEEP_STATE;
44 
CreateStatsdConfig(const GaugeMetric::SamplingType samplingType)45 StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType samplingType) {
46     StatsdConfig config;
47     config.add_allowed_log_source("AID_ROOT");     // LogEvent defaults to UID of root.
48     config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
49     auto atomMatcher = CreateSimpleAtomMatcher("TestMatcher", ATOM_TAG);
50     *config.add_atom_matcher() = atomMatcher;
51     *config.add_gauge_metric() =
52             createGaugeMetric("GAUGE1", atomMatcher.id(), samplingType, nullopt, nullopt);
53     config.set_hash_strings_in_metric_report(false);
54     return config;
55 }
56 
57 class FakeSubsystemSleepCallbackWithTiming : public FakeSubsystemSleepCallback {
58 public:
onPullAtom(int atomTag,const shared_ptr<IPullAtomResultReceiver> & resultReceiver)59     Status onPullAtom(int atomTag,
60                       const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
61         mPullTimeNs = getElapsedRealtimeNs();
62         return FakeSubsystemSleepCallback::onPullAtom(atomTag, resultReceiver);
63     }
64     int64_t mPullTimeNs = 0;
65 };
66 
67 }  // namespace
68 
TEST(StatsServiceTest,TestAddConfig_simple)69 TEST(StatsServiceTest, TestAddConfig_simple) {
70     const sp<UidMap> uidMap = new UidMap();
71     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
72             uidMap, /* queue */ nullptr, /* LogEventFilter */ nullptr);
73     const int kConfigKey = 12345;
74     const int kCallingUid = 123;
75     StatsdConfig config;
76     config.set_id(kConfigKey);
77     string serialized = config.SerializeAsString();
78 
79     EXPECT_TRUE(service->addConfigurationChecked(kCallingUid, kConfigKey,
80                                                  {serialized.begin(), serialized.end()}));
81     service->removeConfiguration(kConfigKey, kCallingUid);
82     ConfigKey configKey(kCallingUid, kConfigKey);
83     service->mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
84                                       false /* include_current_bucket*/, true /* erase_data */,
85                                       ADB_DUMP, NO_TIME_CONSTRAINTS, nullptr);
86 }
87 
TEST(StatsServiceTest,TestAddConfig_empty)88 TEST(StatsServiceTest, TestAddConfig_empty) {
89     const sp<UidMap> uidMap = new UidMap();
90     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
91             uidMap, /* queue */ nullptr, /* LogEventFilter */ nullptr);
92     string serialized = "";
93     const int kConfigKey = 12345;
94     const int kCallingUid = 123;
95     EXPECT_TRUE(service->addConfigurationChecked(kCallingUid, kConfigKey,
96                                                  {serialized.begin(), serialized.end()}));
97     service->removeConfiguration(kConfigKey, kCallingUid);
98     ConfigKey configKey(kCallingUid, kConfigKey);
99     service->mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
100                                       false /* include_current_bucket*/, true /* erase_data */,
101                                       ADB_DUMP, NO_TIME_CONSTRAINTS, nullptr);
102 }
103 
TEST(StatsServiceTest,TestAddConfig_invalid)104 TEST(StatsServiceTest, TestAddConfig_invalid) {
105     const sp<UidMap> uidMap = new UidMap();
106     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
107             uidMap, /* queue */ nullptr, /* LogEventFilter */ nullptr);
108     string serialized = "Invalid config!";
109 
110     EXPECT_FALSE(
111             service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
112 }
113 
TEST(StatsServiceTest,TestGetUidFromArgs)114 TEST(StatsServiceTest, TestGetUidFromArgs) {
115     Vector<String8> args;
116     args.push(String8("-1"));
117     args.push(String8("0"));
118     args.push(String8("1"));
119     args.push(String8("a1"));
120     args.push(String8(""));
121 
122     int32_t uid;
123 
124     const sp<UidMap> uidMap = new UidMap();
125     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
126             uidMap, /* queue */ nullptr, /* LogEventFilter */ nullptr);
127     service->mEngBuild = true;
128 
129     // "-1"
130     EXPECT_FALSE(service->getUidFromArgs(args, 0, uid));
131 
132     // "0"
133     EXPECT_TRUE(service->getUidFromArgs(args, 1, uid));
134     EXPECT_EQ(0, uid);
135 
136     // "1"
137     EXPECT_TRUE(service->getUidFromArgs(args, 2, uid));
138     EXPECT_EQ(1, uid);
139 
140     // "a1"
141     EXPECT_FALSE(service->getUidFromArgs(args, 3, uid));
142 
143     // ""
144     EXPECT_FALSE(service->getUidFromArgs(args, 4, uid));
145 
146     // For a non-userdebug, uid "1" cannot be impersonated.
147     service->mEngBuild = false;
148     EXPECT_FALSE(service->getUidFromArgs(args, 2, uid));
149 }
150 
151 class StatsServiceStatsdInitTest : public StatsServiceConfigTest,
152                                    public testing::WithParamInterface<bool> {
153 public:
StatsServiceStatsdInitTest()154     StatsServiceStatsdInitTest() : kInitDelaySec(GetParam() ? 0 : 3) {
155     }
156 
ToString(testing::TestParamInfo<bool> info)157     static std::string ToString(testing::TestParamInfo<bool> info) {
158         return info.param ? "NoDelay" : "WithDelay";
159     }
160 
161 protected:
162     const int kInitDelaySec = 0;
163 
createStatsService()164     shared_ptr<StatsService> createStatsService() override {
165         return SharedRefBase::make<StatsService>(new UidMap(), /*queue=*/nullptr,
166                                                  /*LogEventFilter=*/nullptr,
167                                                  /*initEventDelaySecs=*/kInitDelaySec);
168     }
169 };
170 
171 INSTANTIATE_TEST_SUITE_P(StatsServiceStatsdInitTest, StatsServiceStatsdInitTest, testing::Bool(),
172                          StatsServiceStatsdInitTest::ToString);
173 
TEST_P(StatsServiceStatsdInitTest,StatsServiceStatsdInitTest)174 TEST_P(StatsServiceStatsdInitTest, StatsServiceStatsdInitTest) {
175     // used for error threshold tolerance due to sleep() is involved
176     const int64_t ERROR_THRESHOLD_NS = GetParam() ? 1000000 : 5 * 1000000;
177 
178     auto pullAtomCallback = SharedRefBase::make<FakeSubsystemSleepCallbackWithTiming>();
179 
180     // TODO: evaluate to use service->registerNativePullAtomCallback() API
181     service->mPullerManager->RegisterPullAtomCallback(/*uid=*/0, ATOM_TAG, NS_PER_SEC,
182                                                       NS_PER_SEC * 10, {}, pullAtomCallback);
183 
184     const int64_t createConfigTimeNs = getElapsedRealtimeNs();
185     StatsdConfig config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
186     config.set_id(kConfigKey);
187     ASSERT_TRUE(sendConfig(config));
188     ASSERT_EQ(2, pullAtomCallback->pullNum);
189 
190     service->mProcessor->mPullerManager->ForceClearPullerCache();
191 
192     const int64_t initCompletedTimeNs = getElapsedRealtimeNs();
193     service->onStatsdInitCompleted();
194     ASSERT_EQ(3, pullAtomCallback->pullNum);
195 
196     // Checking pull with or without delay according to the flag value
197     const int64_t lastPullNs = pullAtomCallback->mPullTimeNs;
198 
199     if (GetParam()) {
200         // when flag is defined - should be small delay between init & pull
201         // expect delay smaller than 1 second
202         EXPECT_GE(lastPullNs, initCompletedTimeNs);
203         EXPECT_LE(lastPullNs, initCompletedTimeNs + ERROR_THRESHOLD_NS);
204     } else {
205         // when flag is not defined - big delay is expected (kInitDelaySec)
206         EXPECT_GE(lastPullNs, initCompletedTimeNs + kInitDelaySec * NS_PER_SEC);
207         EXPECT_LE(lastPullNs,
208                   initCompletedTimeNs + kInitDelaySec * NS_PER_SEC + ERROR_THRESHOLD_NS);
209     }
210 
211     const int64_t bucketSizeNs =
212             TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
213     const int64_t dumpReportTsNanos = createConfigTimeNs + bucketSizeNs + NS_PER_SEC;
214 
215     vector<uint8_t> output;
216     ConfigKey configKey(kCallingUid, kConfigKey);
217     service->mProcessor->onDumpReport(configKey, dumpReportTsNanos,
218                                       /*include_current_bucket=*/false, /*erase_data=*/true,
219                                       ADB_DUMP, FAST, &output);
220     ConfigMetricsReportList reports;
221     reports.ParseFromArray(output.data(), output.size());
222     ASSERT_EQ(1, reports.reports_size());
223 
224     backfillDimensionPath(&reports);
225     backfillStartEndTimestamp(&reports);
226     backfillAggregatedAtoms(&reports);
227     StatsLogReport::GaugeMetricDataWrapper gaugeMetrics =
228             reports.reports(0).metrics(0).gauge_metrics();
229     ASSERT_EQ(gaugeMetrics.skipped_size(), 0);
230     ASSERT_GT((int)gaugeMetrics.data_size(), 0);
231     const auto data = gaugeMetrics.data(0);
232     ASSERT_EQ(2, data.bucket_info_size());
233 
234     const auto bucketInfo0 = data.bucket_info(0);
235     const auto bucketInfo1 = data.bucket_info(1);
236 
237     EXPECT_GE(NanoToMillis(bucketInfo0.start_bucket_elapsed_nanos()),
238               NanoToMillis(createConfigTimeNs));
239     EXPECT_LE(NanoToMillis(bucketInfo0.start_bucket_elapsed_nanos()),
240               NanoToMillis(createConfigTimeNs + ERROR_THRESHOLD_NS));
241 
242     EXPECT_EQ(NanoToMillis(bucketInfo0.end_bucket_elapsed_nanos()),
243               NanoToMillis(bucketInfo1.start_bucket_elapsed_nanos()));
244 
245     ASSERT_EQ(1, bucketInfo1.atom_size());
246     ASSERT_GT(bucketInfo1.atom(0).subsystem_sleep_state().time_millis(), 0);
247 
248     EXPECT_GE(NanoToMillis(bucketInfo1.start_bucket_elapsed_nanos()),
249               NanoToMillis(createConfigTimeNs + kInitDelaySec * NS_PER_SEC));
250     EXPECT_LE(NanoToMillis(bucketInfo1.start_bucket_elapsed_nanos()),
251               NanoToMillis(createConfigTimeNs + kInitDelaySec * NS_PER_SEC + ERROR_THRESHOLD_NS));
252 
253     EXPECT_GE(NanoToMillis(createConfigTimeNs + bucketSizeNs),
254               NanoToMillis(bucketInfo1.end_bucket_elapsed_nanos()));
255     EXPECT_LE(NanoToMillis(createConfigTimeNs + bucketSizeNs),
256               NanoToMillis(bucketInfo1.end_bucket_elapsed_nanos() + ERROR_THRESHOLD_NS));
257 }
258 
259 #else
260 GTEST_LOG_(INFO) << "This test does nothing.\n";
261 #endif
262 
263 }  // namespace statsd
264 }  // namespace os
265 }  // namespace android
266