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