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