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