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 <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 #include <private/android_filesystem_config.h>
18 #include <stdio.h>
19
20 #include <set>
21 #include <unordered_map>
22 #include <vector>
23
24 #include "metrics/metrics_test_helper.h"
25 #include "src/condition/ConditionTracker.h"
26 #include "src/matchers/AtomMatchingTracker.h"
27 #include "src/metrics/CountMetricProducer.h"
28 #include "src/metrics/GaugeMetricProducer.h"
29 #include "src/metrics/MetricProducer.h"
30 #include "src/metrics/NumericValueMetricProducer.h"
31 #include "src/metrics/parsing_utils/metrics_manager_util.h"
32 #include "src/state/StateManager.h"
33 #include "src/statsd_config.pb.h"
34 #include "statsd_test_util.h"
35
36 using namespace testing;
37 using android::sp;
38 using android::modules::sdklevel::IsAtLeastS;
39 using android::modules::sdklevel::IsAtLeastU;
40 using android::os::statsd::Predicate;
41 using std::map;
42 using std::set;
43 using std::unordered_map;
44 using std::vector;
45
46 #ifdef __ANDROID__
47
48 namespace android {
49 namespace os {
50 namespace statsd {
51
52 namespace {
53 const ConfigKey kConfigKey(0, 12345);
54
55 const long timeBaseSec = 1000;
56
buildGoodConfig()57 StatsdConfig buildGoodConfig() {
58 StatsdConfig config;
59 config.set_id(12345);
60
61 AtomMatcher* eventMatcher = config.add_atom_matcher();
62 eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
63
64 SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
65 simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
66 simpleAtomMatcher->add_field_value_matcher()->set_field(
67 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
68 simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
69 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
70
71 eventMatcher = config.add_atom_matcher();
72 eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
73
74 simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
75 simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
76 simpleAtomMatcher->add_field_value_matcher()->set_field(
77 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
78 simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
79 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
80
81 eventMatcher = config.add_atom_matcher();
82 eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
83
84 AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
85 combination->set_operation(LogicalOperation::OR);
86 combination->add_matcher(StringToId("SCREEN_IS_ON"));
87 combination->add_matcher(StringToId("SCREEN_IS_OFF"));
88
89 CountMetric* metric = config.add_count_metric();
90 metric->set_id(3);
91 metric->set_what(StringToId("SCREEN_IS_ON"));
92 metric->set_bucket(ONE_MINUTE);
93 metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
94 metric->mutable_dimensions_in_what()->add_child()->set_field(1);
95 return config;
96 }
97
buildGoodRestrictedConfig()98 StatsdConfig buildGoodRestrictedConfig() {
99 StatsdConfig config;
100 config.set_id(12345);
101 config.set_restricted_metrics_delegate_package_name("delegate");
102
103 AtomMatcher* eventMatcher = config.add_atom_matcher();
104 eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
105 SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
106 simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
107
108 EventMetric* metric = config.add_event_metric();
109 metric->set_id(3);
110 metric->set_what(StringToId("SCREEN_IS_ON"));
111 return config;
112 }
113
unionSet(const vector<set<int32_t>> sets)114 set<int32_t> unionSet(const vector<set<int32_t>> sets) {
115 set<int32_t> toRet;
116 for (const set<int32_t>& s : sets) {
117 toRet.insert(s.begin(), s.end());
118 }
119 return toRet;
120 }
121 } // anonymous namespace
122
TEST(MetricsManagerTest,TestLogSources)123 TEST(MetricsManagerTest, TestLogSources) {
124 string app1 = "app1";
125 set<int32_t> app1Uids = {1111, 11111};
126 string app2 = "app2";
127 set<int32_t> app2Uids = {2222};
128 string app3 = "app3";
129 set<int32_t> app3Uids = {3333, 1111};
130
131 map<string, set<int32_t>> pkgToUids;
132 pkgToUids[app1] = app1Uids;
133 pkgToUids[app2] = app2Uids;
134 pkgToUids[app3] = app3Uids;
135
136 int32_t atom1 = 10, atom2 = 20, atom3 = 30;
137 sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
138 EXPECT_CALL(*uidMap, getAppUid(_))
139 .Times(4)
140 .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) {
141 const auto& it = pkgToUids.find(pkg);
142 if (it != pkgToUids.end()) {
143 return it->second;
144 }
145 return set<int32_t>();
146 }));
147 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
148 EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1);
149 EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1);
150
151 sp<AlarmMonitor> anomalyAlarmMonitor;
152 sp<AlarmMonitor> periodicAlarmMonitor;
153
154 StatsdConfig config;
155 config.add_allowed_log_source("AID_SYSTEM");
156 config.add_allowed_log_source(app1);
157 config.add_default_pull_packages("AID_SYSTEM");
158 config.add_default_pull_packages("AID_ROOT");
159
160 const set<int32_t> defaultPullUids = {AID_SYSTEM, AID_ROOT};
161
162 PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages();
163 pullAtomPackages->set_atom_id(atom1);
164 pullAtomPackages->add_packages(app1);
165 pullAtomPackages->add_packages(app3);
166
167 pullAtomPackages = config.add_pull_atom_packages();
168 pullAtomPackages->set_atom_id(atom2);
169 pullAtomPackages->add_packages(app2);
170 pullAtomPackages->add_packages("AID_STATSD");
171
172 MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
173 pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
174 EXPECT_TRUE(metricsManager.isConfigValid());
175
176 EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_SYSTEM));
177 EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app1));
178 EXPECT_THAT(metricsManager.mAllowedLogSources,
179 ContainerEq(unionSet(vector<set<int32_t>>({app1Uids, {AID_SYSTEM}}))));
180 EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
181
182 vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
183 EXPECT_THAT(atom1Uids,
184 UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
185
186 vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
187 EXPECT_THAT(atom2Uids,
188 UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_STATSD}})));
189
190 vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
191 EXPECT_THAT(atom3Uids, UnorderedElementsAreArray(defaultPullUids));
192 }
193
TEST(MetricsManagerTest,TestLogSourcesOnConfigUpdate)194 TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate) {
195 string app1 = "app1";
196 set<int32_t> app1Uids = {1111, 11111};
197 string app2 = "app2";
198 set<int32_t> app2Uids = {2222};
199 string app3 = "app3";
200 set<int32_t> app3Uids = {3333, 1111};
201
202 map<string, set<int32_t>> pkgToUids;
203 pkgToUids[app1] = app1Uids;
204 pkgToUids[app2] = app2Uids;
205 pkgToUids[app3] = app3Uids;
206
207 int32_t atom1 = 10, atom2 = 20, atom3 = 30;
208 sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
209 EXPECT_CALL(*uidMap, getAppUid(_))
210 .Times(8)
211 .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) {
212 const auto& it = pkgToUids.find(pkg);
213 if (it != pkgToUids.end()) {
214 return it->second;
215 }
216 return set<int32_t>();
217 }));
218 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
219 EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1);
220 EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1);
221
222 sp<AlarmMonitor> anomalyAlarmMonitor;
223 sp<AlarmMonitor> periodicAlarmMonitor;
224
225 StatsdConfig config;
226 config.add_allowed_log_source("AID_SYSTEM");
227 config.add_allowed_log_source(app1);
228 config.add_default_pull_packages("AID_SYSTEM");
229 config.add_default_pull_packages("AID_ROOT");
230
231 PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages();
232 pullAtomPackages->set_atom_id(atom1);
233 pullAtomPackages->add_packages(app1);
234 pullAtomPackages->add_packages(app3);
235
236 pullAtomPackages = config.add_pull_atom_packages();
237 pullAtomPackages->set_atom_id(atom2);
238 pullAtomPackages->add_packages(app2);
239 pullAtomPackages->add_packages("AID_STATSD");
240
241 MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
242 pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
243 EXPECT_TRUE(metricsManager.isConfigValid());
244
245 // Update with new allowed log sources.
246 StatsdConfig newConfig;
247 newConfig.add_allowed_log_source("AID_ROOT");
248 newConfig.add_allowed_log_source(app2);
249 newConfig.add_default_pull_packages("AID_SYSTEM");
250 newConfig.add_default_pull_packages("AID_STATSD");
251
252 pullAtomPackages = newConfig.add_pull_atom_packages();
253 pullAtomPackages->set_atom_id(atom2);
254 pullAtomPackages->add_packages(app1);
255 pullAtomPackages->add_packages(app3);
256
257 pullAtomPackages = newConfig.add_pull_atom_packages();
258 pullAtomPackages->set_atom_id(atom3);
259 pullAtomPackages->add_packages(app2);
260 pullAtomPackages->add_packages("AID_ADB");
261
262 metricsManager.updateConfig(newConfig, timeBaseSec, timeBaseSec, anomalyAlarmMonitor,
263 periodicAlarmMonitor);
264 EXPECT_TRUE(metricsManager.isConfigValid());
265
266 EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_ROOT));
267 EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app2));
268 EXPECT_THAT(metricsManager.mAllowedLogSources,
269 ContainerEq(unionSet(vector<set<int32_t>>({app2Uids, {AID_ROOT}}))));
270 const set<int32_t> defaultPullUids = {AID_SYSTEM, AID_STATSD};
271 EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
272
273 vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
274 EXPECT_THAT(atom1Uids, UnorderedElementsAreArray(defaultPullUids));
275
276 vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
277 EXPECT_THAT(atom2Uids,
278 UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
279
280 vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
281 EXPECT_THAT(atom3Uids,
282 UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_ADB}})));
283 }
284
285 struct MetricsManagerServerFlagParam {
286 string flagValue;
287 string label;
288 };
289
290 class MetricsManagerTest_SPlus
291 : public ::testing::Test,
292 public ::testing::WithParamInterface<MetricsManagerServerFlagParam> {
293 protected:
SetUp()294 void SetUp() override {
295 if (shouldSkipTest()) {
296 GTEST_SKIP() << skipReason();
297 }
298 }
299
shouldSkipTest() const300 bool shouldSkipTest() const {
301 return !IsAtLeastS();
302 }
303
skipReason() const304 string skipReason() const {
305 return "Skipping MetricsManagerTest_SPlus because device is not S+";
306 }
307
308 std::optional<string> originalFlagValue;
309 };
310
311 INSTANTIATE_TEST_SUITE_P(
312 MetricsManagerTest_SPlus, MetricsManagerTest_SPlus,
313 testing::ValuesIn<MetricsManagerServerFlagParam>({
314 // Server flag values
315 {FLAG_TRUE, "ServerFlagTrue"},
316 {FLAG_FALSE, "ServerFlagFalse"},
317 }),
__anonee29e5420402(const testing::TestParamInfo<MetricsManagerTest_SPlus::ParamType>& info) 318 [](const testing::TestParamInfo<MetricsManagerTest_SPlus::ParamType>& info) {
319 return info.param.label;
320 });
321
TEST(MetricsManagerTest,TestCheckLogCredentialsWhitelistedAtom)322 TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) {
323 sp<UidMap> uidMap;
324 sp<StatsPullerManager> pullerManager = new StatsPullerManager();
325 sp<AlarmMonitor> anomalyAlarmMonitor;
326 sp<AlarmMonitor> periodicAlarmMonitor;
327
328 StatsdConfig config;
329 config.add_whitelisted_atom_ids(3);
330 config.add_whitelisted_atom_ids(4);
331
332 MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
333 pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
334
335 LogEvent event(0 /* uid */, 0 /* pid */);
336 CreateNoValuesLogEvent(&event, 10 /* atom id */, 0 /* timestamp */);
337 EXPECT_FALSE(metricsManager.checkLogCredentials(event));
338
339 CreateNoValuesLogEvent(&event, 3 /* atom id */, 0 /* timestamp */);
340 EXPECT_TRUE(metricsManager.checkLogCredentials(event));
341
342 CreateNoValuesLogEvent(&event, 4 /* atom id */, 0 /* timestamp */);
343 EXPECT_TRUE(metricsManager.checkLogCredentials(event));
344 }
345
TEST(MetricsManagerTest,TestWhitelistedAtomStateTracker)346 TEST(MetricsManagerTest, TestWhitelistedAtomStateTracker) {
347 sp<UidMap> uidMap;
348 sp<StatsPullerManager> pullerManager = new StatsPullerManager();
349 sp<AlarmMonitor> anomalyAlarmMonitor;
350 sp<AlarmMonitor> periodicAlarmMonitor;
351
352 StatsdConfig config = buildGoodConfig();
353 config.add_allowed_log_source("AID_SYSTEM");
354 config.add_whitelisted_atom_ids(3);
355 config.add_whitelisted_atom_ids(4);
356
357 State state;
358 state.set_id(1);
359 state.set_atom_id(3);
360
361 *config.add_state() = state;
362
363 config.mutable_count_metric(0)->add_slice_by_state(state.id());
364
365 StateManager::getInstance().clear();
366
367 MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
368 pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
369
370 EXPECT_EQ(0, StateManager::getInstance().getStateTrackersCount());
371 EXPECT_FALSE(metricsManager.isConfigValid());
372 }
373
TEST_P(MetricsManagerTest_SPlus,TestRestrictedMetricsConfig)374 TEST_P(MetricsManagerTest_SPlus, TestRestrictedMetricsConfig) {
375 sp<UidMap> uidMap;
376 sp<StatsPullerManager> pullerManager = new StatsPullerManager();
377 sp<AlarmMonitor> anomalyAlarmMonitor;
378 sp<AlarmMonitor> periodicAlarmMonitor;
379
380 StatsdConfig config = buildGoodRestrictedConfig();
381 config.add_allowed_log_source("AID_SYSTEM");
382 config.set_restricted_metrics_delegate_package_name("rm");
383
384 MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
385 pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
386
387 if (IsAtLeastU()) {
388 EXPECT_TRUE(metricsManager.isConfigValid());
389 } else {
390 EXPECT_EQ(metricsManager.mInvalidConfigReason,
391 INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_ENABLED);
392 ASSERT_FALSE(metricsManager.isConfigValid());
393 }
394 }
395
TEST_P(MetricsManagerTest_SPlus,TestRestrictedMetricsConfigUpdate)396 TEST_P(MetricsManagerTest_SPlus, TestRestrictedMetricsConfigUpdate) {
397 sp<UidMap> uidMap;
398 sp<StatsPullerManager> pullerManager = new StatsPullerManager();
399 sp<AlarmMonitor> anomalyAlarmMonitor;
400 sp<AlarmMonitor> periodicAlarmMonitor;
401
402 StatsdConfig config = buildGoodRestrictedConfig();
403 config.add_allowed_log_source("AID_SYSTEM");
404 config.set_restricted_metrics_delegate_package_name("rm");
405
406 MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
407 pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
408
409 StatsdConfig config2 = buildGoodRestrictedConfig();
410 metricsManager.updateConfig(config, timeBaseSec, timeBaseSec, anomalyAlarmMonitor,
411 periodicAlarmMonitor);
412
413 if (IsAtLeastU()) {
414 EXPECT_TRUE(metricsManager.isConfigValid());
415 } else {
416 EXPECT_EQ(metricsManager.mInvalidConfigReason,
417 INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_ENABLED);
418 ASSERT_FALSE(metricsManager.isConfigValid());
419 }
420 }
421
422 } // namespace statsd
423 } // namespace os
424 } // namespace android
425
426 #else
427 GTEST_LOG_(INFO) << "This test does nothing.\n";
428 #endif
429