1 // Copyright (C) 2023 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 <android-modules-utils/sdk_level.h>
16 #include <gtest/gtest.h>
17
18 #include "flags/FlagProvider.h"
19 #include "storage/StorageManager.h"
20 #include "tests/statsd_test_util.h"
21
22 namespace android {
23 namespace os {
24 namespace statsd {
25
26 using android::modules::sdklevel::IsAtLeastU;
27
28 #ifdef __ANDROID__
29
30 namespace {
31 const int32_t atomTag = 666;
32 const string delegatePackageName = "com.test.restricted.metrics.package";
33 const int32_t delegateUid = 10200;
34 const string configPackageName = "com.test.config.package";
35 int64_t metricId;
36 int64_t anotherMetricId;
37
CreateConfigWithOneMetric()38 StatsdConfig CreateConfigWithOneMetric() {
39 StatsdConfig config;
40 config.add_allowed_log_source("AID_ROOT");
41 AtomMatcher atomMatcher = CreateSimpleAtomMatcher("testmatcher", atomTag);
42 *config.add_atom_matcher() = atomMatcher;
43
44 EventMetric eventMetric = createEventMetric("EventMetric", atomMatcher.id(), nullopt);
45 metricId = eventMetric.id();
46 *config.add_event_metric() = eventMetric;
47 return config;
48 }
CreateConfigWithTwoMetrics()49 StatsdConfig CreateConfigWithTwoMetrics() {
50 StatsdConfig config;
51 config.add_allowed_log_source("AID_ROOT");
52 AtomMatcher atomMatcher = CreateSimpleAtomMatcher("testmatcher", atomTag);
53 *config.add_atom_matcher() = atomMatcher;
54
55 EventMetric eventMetric = createEventMetric("EventMetric", atomMatcher.id(), nullopt);
56 metricId = eventMetric.id();
57 *config.add_event_metric() = eventMetric;
58 EventMetric anotherEventMetric =
59 createEventMetric("AnotherEventMetric", atomMatcher.id(), nullopt);
60 anotherMetricId = anotherEventMetric.id();
61 *config.add_event_metric() = anotherEventMetric;
62 return config;
63 }
64
CreateLogEvents(int64_t configAddedTimeNs)65 std::vector<std::unique_ptr<LogEvent>> CreateLogEvents(int64_t configAddedTimeNs) {
66 std::vector<std::unique_ptr<LogEvent>> events;
67 events.push_back(CreateNonRestrictedLogEvent(atomTag, configAddedTimeNs + 10 * NS_PER_SEC));
68 events.push_back(CreateNonRestrictedLogEvent(atomTag, configAddedTimeNs + 20 * NS_PER_SEC));
69 events.push_back(CreateNonRestrictedLogEvent(atomTag, configAddedTimeNs + 30 * NS_PER_SEC));
70 return events;
71 }
72
73 } // Anonymous namespace
74
75 class RestrictedConfigE2ETest : public StatsServiceConfigTest {
76 protected:
77 shared_ptr<MockStatsQueryCallback> mockStatsQueryCallback;
78 const ConfigKey configKey = ConfigKey(kCallingUid, kConfigKey);
79 vector<string> queryDataResult;
80 vector<string> columnNamesResult;
81 vector<int32_t> columnTypesResult;
82 int32_t rowCountResult = 0;
83 string error;
84
SetUp()85 void SetUp() override {
86 if (!IsAtLeastU()) {
87 GTEST_SKIP();
88 }
89 StatsServiceConfigTest::SetUp();
90
91 mockStatsQueryCallback = SharedRefBase::make<StrictMock<MockStatsQueryCallback>>();
92 EXPECT_CALL(*mockStatsQueryCallback, sendResults(_, _, _, _))
93 .Times(AnyNumber())
94 .WillRepeatedly(Invoke(
95 [this](const vector<string>& queryData, const vector<string>& columnNames,
96 const vector<int32_t>& columnTypes, int32_t rowCount) {
97 queryDataResult = queryData;
98 columnNamesResult = columnNames;
99 columnTypesResult = columnTypes;
100 rowCountResult = rowCount;
101 error = "";
102 return Status::ok();
103 }));
104 EXPECT_CALL(*mockStatsQueryCallback, sendFailure(_))
105 .Times(AnyNumber())
106 .WillRepeatedly(Invoke([this](const string& err) {
107 error = err;
108 queryDataResult.clear();
109 columnNamesResult.clear();
110 columnTypesResult.clear();
111 rowCountResult = 0;
112 return Status::ok();
113 }));
114
115 int64_t startTimeNs = getElapsedRealtimeNs();
116 service->mUidMap->updateMap(
117 startTimeNs, {delegateUid, kCallingUid},
118 /*versionCode=*/{1, 1}, /*versionString=*/{String16("v2"), String16("v2")},
119 {String16(delegatePackageName.c_str()), String16(configPackageName.c_str())},
120 /*installer=*/{String16(), String16()}, /*certificateHash=*/{{}, {}});
121 }
TearDown()122 void TearDown() override {
123 if (!IsAtLeastU()) {
124 GTEST_SKIP();
125 }
126 Mock::VerifyAndClear(mockStatsQueryCallback.get());
127 queryDataResult.clear();
128 columnNamesResult.clear();
129 columnTypesResult.clear();
130 rowCountResult = 0;
131 error = "";
132 StatsServiceConfigTest::TearDown();
133 FlagProvider::getInstance().resetOverrides();
134 dbutils::deleteDb(configKey);
135 }
136
verifyRestrictedData(int32_t expectedNumOfMetrics,int64_t metricIdToVerify=metricId,bool shouldExist=true)137 void verifyRestrictedData(int32_t expectedNumOfMetrics, int64_t metricIdToVerify = metricId,
138 bool shouldExist = true) {
139 std::stringstream query;
140 query << "SELECT * FROM metric_" << dbutils::reformatMetricId(metricIdToVerify);
141 string err;
142 std::vector<int32_t> columnTypes;
143 std::vector<string> columnNames;
144 std::vector<std::vector<std::string>> rows;
145 if (shouldExist) {
146 EXPECT_TRUE(
147 dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err));
148 EXPECT_EQ(rows.size(), expectedNumOfMetrics);
149 } else {
150 // Expect that table is deleted.
151 EXPECT_FALSE(
152 dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err));
153 }
154 }
155 };
156
TEST_F(RestrictedConfigE2ETest,RestrictedConfigNoReport)157 TEST_F(RestrictedConfigE2ETest, RestrictedConfigNoReport) {
158 StatsdConfig config = CreateConfigWithOneMetric();
159 config.set_restricted_metrics_delegate_package_name("delegate");
160 sendConfig(config);
161 int64_t configAddedTimeNs = getElapsedRealtimeNs();
162
163 for (auto& event : CreateLogEvents(configAddedTimeNs)) {
164 service->OnLogEvent(event.get());
165 }
166
167 vector<uint8_t> output;
168 ConfigKey configKey(kCallingUid, kConfigKey);
169 service->getData(kConfigKey, kCallingUid, &output);
170
171 EXPECT_TRUE(output.empty());
172 }
173
TEST_F(RestrictedConfigE2ETest,NonRestrictedConfigGetReport)174 TEST_F(RestrictedConfigE2ETest, NonRestrictedConfigGetReport) {
175 StatsdConfig config = CreateConfigWithOneMetric();
176 sendConfig(config);
177 int64_t configAddedTimeNs = getElapsedRealtimeNs();
178
179 for (auto& event : CreateLogEvents(configAddedTimeNs)) {
180 service->OnLogEvent(event.get());
181 }
182
183 ConfigMetricsReport report = getReports(service->mProcessor, /*timestamp=*/10);
184 EXPECT_EQ(report.metrics_size(), 1);
185 }
186
TEST_F(RestrictedConfigE2ETest,RestrictedShutdownFlushToRestrictedDB)187 TEST_F(RestrictedConfigE2ETest, RestrictedShutdownFlushToRestrictedDB) {
188 StatsdConfig config = CreateConfigWithOneMetric();
189 config.set_restricted_metrics_delegate_package_name("delegate");
190 sendConfig(config);
191 int64_t configAddedTimeNs = getElapsedRealtimeNs();
192 std::vector<std::unique_ptr<LogEvent>> logEvents = CreateLogEvents(configAddedTimeNs);
193 for (const auto& e : logEvents) {
194 service->OnLogEvent(e.get());
195 }
196
197 service->informDeviceShutdown();
198
199 // Should not be written to non-restricted storage.
200 EXPECT_FALSE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
201 verifyRestrictedData(logEvents.size());
202 }
203
TEST_F(RestrictedConfigE2ETest,NonRestrictedOnShutdownWriteDataToDisk)204 TEST_F(RestrictedConfigE2ETest, NonRestrictedOnShutdownWriteDataToDisk) {
205 StatsdConfig config = CreateConfigWithOneMetric();
206 sendConfig(config);
207 int64_t configAddedTimeNs = getElapsedRealtimeNs();
208 for (auto& event : CreateLogEvents(configAddedTimeNs)) {
209 service->OnLogEvent(event.get());
210 }
211
212 service->informDeviceShutdown();
213
214 EXPECT_TRUE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
215 }
216
TEST_F(RestrictedConfigE2ETest,RestrictedConfigOnTerminateFlushToRestrictedDB)217 TEST_F(RestrictedConfigE2ETest, RestrictedConfigOnTerminateFlushToRestrictedDB) {
218 StatsdConfig config = CreateConfigWithOneMetric();
219 config.set_restricted_metrics_delegate_package_name("delegate");
220 sendConfig(config);
221 int64_t configAddedTimeNs = getElapsedRealtimeNs();
222 std::vector<std::unique_ptr<LogEvent>> logEvents = CreateLogEvents(configAddedTimeNs);
223 for (auto& event : logEvents) {
224 service->OnLogEvent(event.get());
225 }
226
227 service->Terminate();
228
229 EXPECT_FALSE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
230 verifyRestrictedData(logEvents.size());
231 }
232
TEST_F(RestrictedConfigE2ETest,NonRestrictedConfigOnTerminateWriteDataToDisk)233 TEST_F(RestrictedConfigE2ETest, NonRestrictedConfigOnTerminateWriteDataToDisk) {
234 StatsdConfig config = CreateConfigWithOneMetric();
235 sendConfig(config);
236 int64_t configAddedTimeNs = getElapsedRealtimeNs();
237 for (auto& event : CreateLogEvents(configAddedTimeNs)) {
238 service->OnLogEvent(event.get());
239 }
240
241 service->Terminate();
242
243 EXPECT_TRUE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
244 }
245
TEST_F(RestrictedConfigE2ETest,RestrictedConfigOnUpdateWithMetricRemoval)246 TEST_F(RestrictedConfigE2ETest, RestrictedConfigOnUpdateWithMetricRemoval) {
247 StatsdConfig complexConfig = CreateConfigWithTwoMetrics();
248 complexConfig.set_restricted_metrics_delegate_package_name(delegatePackageName);
249 sendConfig(complexConfig);
250 int64_t configAddedTimeNs = getElapsedRealtimeNs();
251 std::vector<std::unique_ptr<LogEvent>> logEvents = CreateLogEvents(configAddedTimeNs);
252 for (auto& event : logEvents) {
253 service->OnLogEvent(event.get());
254 }
255
256 // Use query API to make sure data is flushed.
257 std::stringstream query;
258 query << "SELECT * FROM metric_" << dbutils::reformatMetricId(metricId);
259 service->querySql(query.str(), /*minSqlClientVersion=*/0,
260 /*policyConfig=*/{}, mockStatsQueryCallback,
261 /*configKey=*/kConfigKey, /*configPackage=*/configPackageName,
262 /*callingUid=*/delegateUid);
263 EXPECT_EQ(error, "");
264 EXPECT_EQ(rowCountResult, logEvents.size());
265 verifyRestrictedData(logEvents.size(), anotherMetricId, true);
266
267 // Update config to have only one metric
268 StatsdConfig config = CreateConfigWithOneMetric();
269 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
270 sendConfig(config);
271
272 // Make sure metric data is deleted.
273 verifyRestrictedData(logEvents.size(), metricId, true);
274 verifyRestrictedData(logEvents.size(), anotherMetricId, false);
275 }
276
TEST_F(RestrictedConfigE2ETest,TestSendRestrictedMetricsChangedBroadcast)277 TEST_F(RestrictedConfigE2ETest, TestSendRestrictedMetricsChangedBroadcast) {
278 vector<int64_t> receivedMetricIds;
279 int receiveCount = 0;
280 shared_ptr<MockPendingIntentRef> pir = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
281 EXPECT_CALL(*pir, sendRestrictedMetricsChangedBroadcast(_))
282 .Times(7)
283 .WillRepeatedly(Invoke([&receivedMetricIds, &receiveCount](const vector<int64_t>& ids) {
284 receiveCount++;
285 receivedMetricIds = ids;
286 return Status::ok();
287 }));
288
289 // Set the operation. No configs present so empty list is returned.
290 vector<int64_t> returnedMetricIds;
291 service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
292 &returnedMetricIds);
293 EXPECT_EQ(receiveCount, 0);
294 EXPECT_THAT(returnedMetricIds, IsEmpty());
295
296 // Add restricted config. Should receive one metric
297 StatsdConfig config = CreateConfigWithOneMetric();
298 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
299 sendConfig(config);
300 EXPECT_EQ(receiveCount, 1);
301 EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
302
303 // Config update, should receive two metrics.
304 config = CreateConfigWithTwoMetrics();
305 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
306 sendConfig(config);
307 EXPECT_EQ(receiveCount, 2);
308 EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId, anotherMetricId));
309
310 // Make config unrestricted. Should receive empty list.
311 config.clear_restricted_metrics_delegate_package_name();
312 sendConfig(config);
313 EXPECT_EQ(receiveCount, 3);
314 EXPECT_THAT(receivedMetricIds, IsEmpty());
315
316 // Update the unrestricted config. Nothing should be sent.
317 config = CreateConfigWithOneMetric();
318 sendConfig(config);
319
320 // Update config and make it restricted. Should receive one metric.
321 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
322 sendConfig(config);
323 EXPECT_EQ(receiveCount, 4);
324 EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
325
326 // Send an invalid config. Should receive empty list.
327 config.clear_allowed_log_source();
328 sendConfig(config);
329 EXPECT_EQ(receiveCount, 5);
330 EXPECT_THAT(receivedMetricIds, IsEmpty());
331
332 service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
333
334 // Nothing should be sent since the operation is removed.
335 config = CreateConfigWithTwoMetrics();
336 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
337 sendConfig(config);
338
339 // Set the operation. Two metrics should be returned.
340 returnedMetricIds.clear();
341 service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
342 &returnedMetricIds);
343 EXPECT_THAT(returnedMetricIds, UnorderedElementsAre(metricId, anotherMetricId));
344 EXPECT_EQ(receiveCount, 5);
345
346 // Config update, should receive two metrics.
347 config = CreateConfigWithOneMetric();
348 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
349 sendConfig(config);
350 EXPECT_EQ(receiveCount, 6);
351 EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
352
353 // Remove the config and verify an empty list is received
354 service->removeConfiguration(kConfigKey, kCallingUid);
355 EXPECT_EQ(receiveCount, 7);
356 EXPECT_THAT(receivedMetricIds, IsEmpty());
357
358 // Cleanup.
359 service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
360 }
361
TEST_F(RestrictedConfigE2ETest,TestSendRestrictedMetricsChangedBroadcastMultipleListeners)362 TEST_F(RestrictedConfigE2ETest, TestSendRestrictedMetricsChangedBroadcastMultipleListeners) {
363 const string configPackageName2 = "com.test.config.package2";
364 const int32_t delegateUid2 = delegateUid + 1, delegateUid3 = delegateUid + 2;
365 service->informOnePackage(configPackageName2, kCallingUid, 0, "", "", {});
366 service->informOnePackage(delegatePackageName, delegateUid2, 0, "", "", {});
367 service->informOnePackage("not.a.good.package", delegateUid3, 0, "", "", {});
368
369 vector<int64_t> receivedMetricIds;
370 int receiveCount = 0;
371 shared_ptr<MockPendingIntentRef> pir = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
372 EXPECT_CALL(*pir, sendRestrictedMetricsChangedBroadcast(_))
373 .Times(2)
374 .WillRepeatedly(Invoke([&receivedMetricIds, &receiveCount](const vector<int64_t>& ids) {
375 receiveCount++;
376 receivedMetricIds = ids;
377 return Status::ok();
378 }));
379
380 int receiveCount2 = 0;
381 vector<int64_t> receivedMetricIds2;
382 shared_ptr<MockPendingIntentRef> pir2 = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
383 EXPECT_CALL(*pir2, sendRestrictedMetricsChangedBroadcast(_))
384 .Times(2)
385 .WillRepeatedly(
386 Invoke([&receivedMetricIds2, &receiveCount2](const vector<int64_t>& ids) {
387 receiveCount2++;
388 receivedMetricIds2 = ids;
389 return Status::ok();
390 }));
391
392 // This one should never be called.
393 shared_ptr<MockPendingIntentRef> pir3 = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
394 EXPECT_CALL(*pir3, sendRestrictedMetricsChangedBroadcast(_)).Times(0);
395
396 // Set the operations. No configs present so empty list is returned.
397 vector<int64_t> returnedMetricIds;
398 service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
399 &returnedMetricIds);
400 EXPECT_EQ(receiveCount, 0);
401 EXPECT_THAT(returnedMetricIds, IsEmpty());
402
403 vector<int64_t> returnedMetricIds2;
404 service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName2, pir2,
405 delegateUid2, &returnedMetricIds2);
406 EXPECT_EQ(receiveCount2, 0);
407 EXPECT_THAT(returnedMetricIds2, IsEmpty());
408
409 // Represents a package listening for changes but doesn't match the restricted package in the
410 // config.
411 vector<int64_t> returnedMetricIds3;
412 service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir3, delegateUid3,
413 &returnedMetricIds3);
414 EXPECT_THAT(returnedMetricIds3, IsEmpty());
415
416 // Add restricted config. Should receive one metric on pir1 and 2.
417 StatsdConfig config = CreateConfigWithOneMetric();
418 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
419 sendConfig(config);
420 EXPECT_EQ(receiveCount, 1);
421 EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
422 EXPECT_EQ(receiveCount2, 1);
423 EXPECT_THAT(receivedMetricIds2, UnorderedElementsAre(metricId));
424
425 // Config update, should receive two metrics on pir1 and 2.
426 config = CreateConfigWithTwoMetrics();
427 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
428 sendConfig(config);
429 EXPECT_EQ(receiveCount, 2);
430 EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId, anotherMetricId));
431 EXPECT_EQ(receiveCount2, 2);
432 EXPECT_THAT(receivedMetricIds2, UnorderedElementsAre(metricId, anotherMetricId));
433
434 // Cleanup.
435 service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
436 service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName2, delegateUid2);
437 service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid3);
438 }
439
TEST_F(RestrictedConfigE2ETest,TestSendRestrictedMetricsChangedBroadcastMultipleMatchedConfigs)440 TEST_F(RestrictedConfigE2ETest, TestSendRestrictedMetricsChangedBroadcastMultipleMatchedConfigs) {
441 const int32_t callingUid2 = kCallingUid + 1;
442 service->informOnePackage(configPackageName, callingUid2, 0, "", "", {});
443
444 // Add restricted config.
445 StatsdConfig config = CreateConfigWithOneMetric();
446 config.set_restricted_metrics_delegate_package_name(delegatePackageName);
447 sendConfig(config);
448
449 // Add a second config.
450 const int64_t metricId2 = 42;
451 config.mutable_event_metric(0)->set_id(42);
452 string str;
453 config.SerializeToString(&str);
454 std::vector<uint8_t> configAsVec(str.begin(), str.end());
455 service->addConfiguration(kConfigKey, configAsVec, callingUid2);
456
457 // Set the operation. Matches multiple configs so a union of metrics are returned.
458 shared_ptr<MockPendingIntentRef> pir = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
459 vector<int64_t> returnedMetricIds;
460 service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
461 &returnedMetricIds);
462 EXPECT_THAT(returnedMetricIds, UnorderedElementsAre(metricId, metricId2));
463
464 // Cleanup.
465 service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
466
467 ConfigKey cfgKey(callingUid2, kConfigKey);
468 service->removeConfiguration(kConfigKey, callingUid2);
469 service->mProcessor->onDumpReport(cfgKey, getElapsedRealtimeNs(),
470 false /* include_current_bucket*/, true /* erase_data */,
471 ADB_DUMP, NO_TIME_CONSTRAINTS, nullptr);
472 }
473 #else
474 GTEST_LOG_(INFO) << "This test does nothing.\n";
475 #endif
476
477 } // namespace statsd
478 } // namespace os
479 } // namespace android