1 // Copyright (C) 2019 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 "src/storage/StorageManager.h"
16 
17 #include <android-base/unique_fd.h>
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <stdio.h>
21 
22 #include "android-base/stringprintf.h"
23 #include "stats_log_util.h"
24 #include "tests/statsd_test_util.h"
25 #include "utils/DbUtils.h"
26 
27 #ifdef __ANDROID__
28 
29 namespace android {
30 namespace os {
31 namespace statsd {
32 
33 using namespace testing;
34 
35 using std::make_shared;
36 using std::shared_ptr;
37 using std::vector;
38 using testing::Contains;
39 
TEST(StorageManagerTest,TrainInfoReadWriteTest)40 TEST(StorageManagerTest, TrainInfoReadWriteTest) {
41     InstallTrainInfo trainInfo;
42     trainInfo.trainVersionCode = 12345;
43     trainInfo.trainName = "This is a train name #)$(&&$";
44     trainInfo.status = 1;
45     const char* expIds = "test_ids";
46     trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
47 
48     bool result;
49 
50     result = StorageManager::writeTrainInfo(trainInfo);
51 
52     EXPECT_TRUE(result);
53 
54     InstallTrainInfo trainInfoResult;
55     result = StorageManager::readTrainInfo(trainInfo.trainName, trainInfoResult);
56     EXPECT_TRUE(result);
57 
58     EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
59     ASSERT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
60     EXPECT_EQ(trainInfo.trainName, trainInfoResult.trainName);
61     EXPECT_EQ(trainInfo.status, trainInfoResult.status);
62     ASSERT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
63     EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
64 }
65 
TEST(StorageManagerTest,TrainInfoReadWriteTrainNameSizeOneTest)66 TEST(StorageManagerTest, TrainInfoReadWriteTrainNameSizeOneTest) {
67     InstallTrainInfo trainInfo;
68     trainInfo.trainVersionCode = 12345;
69     trainInfo.trainName = "{";
70     trainInfo.status = 1;
71     const char* expIds = "test_ids";
72     trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
73 
74     bool result;
75 
76     result = StorageManager::writeTrainInfo(trainInfo);
77 
78     EXPECT_TRUE(result);
79 
80     InstallTrainInfo trainInfoResult;
81     result = StorageManager::readTrainInfo(trainInfo.trainName, trainInfoResult);
82     EXPECT_TRUE(result);
83 
84     EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
85     ASSERT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
86     EXPECT_EQ(trainInfo.trainName, trainInfoResult.trainName);
87     EXPECT_EQ(trainInfo.status, trainInfoResult.status);
88     ASSERT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
89     EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
90 }
91 
TEST(StorageManagerTest,SortFileTest)92 TEST(StorageManagerTest, SortFileTest) {
93     vector<StorageManager::FileInfo> list;
94     // assume now sec is 500
95     list.emplace_back("200_5000_123454", false, 20, 300);
96     list.emplace_back("300_2000_123454_history", true, 30, 200);
97     list.emplace_back("400_100009_123454_history", true, 40, 100);
98     list.emplace_back("100_2000_123454", false, 50, 400);
99 
100     StorageManager::sortFiles(&list);
101     EXPECT_EQ("200_5000_123454", list[0].mFileName);
102     EXPECT_EQ("100_2000_123454", list[1].mFileName);
103     EXPECT_EQ("400_100009_123454_history", list[2].mFileName);
104     EXPECT_EQ("300_2000_123454_history", list[3].mFileName);
105 }
106 
107 const string testDir = "/data/misc/stats-data/";
108 const string file1 = testDir + "2557169347_1066_1";
109 const string file2 = testDir + "2557169349_1066_1";
110 const string file1_history = file1 + "_history";
111 const string file2_history = file2 + "_history";
112 
prepareLocalHistoryTestFiles()113 bool prepareLocalHistoryTestFiles() {
114     android::base::unique_fd fd(TEMP_FAILURE_RETRY(
115             open(file1.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR)));
116     if (fd != -1) {
117         dprintf(fd, "content");
118     } else {
119         return false;
120     }
121 
122     android::base::unique_fd fd2(TEMP_FAILURE_RETRY(
123             open(file2.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR)));
124     if (fd2 != -1) {
125         dprintf(fd2, "content");
126     } else {
127         return false;
128     }
129     return true;
130 }
131 
clearLocalHistoryTestFiles()132 void clearLocalHistoryTestFiles() {
133     TEMP_FAILURE_RETRY(remove(file1.c_str()));
134     TEMP_FAILURE_RETRY(remove(file2.c_str()));
135     TEMP_FAILURE_RETRY(remove(file1_history.c_str()));
136     TEMP_FAILURE_RETRY(remove(file2_history.c_str()));
137 }
138 
fileExist(string name)139 bool fileExist(string name) {
140     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY | O_CLOEXEC)));
141     return fd != -1;
142 }
143 
144 /* The following AppendConfigReportTests test the 4 combinations of [whether erase data] [whether
145  * the caller is adb] */
TEST(StorageManagerTest,AppendConfigReportTest1)146 TEST(StorageManagerTest, AppendConfigReportTest1) {
147     EXPECT_TRUE(prepareLocalHistoryTestFiles());
148 
149     ProtoOutputStream out;
150     StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, false /*erase?*/,
151                                               false /*isAdb?*/);
152 
153     EXPECT_FALSE(fileExist(file1));
154     EXPECT_FALSE(fileExist(file2));
155 
156     EXPECT_TRUE(fileExist(file1_history));
157     EXPECT_TRUE(fileExist(file2_history));
158     clearLocalHistoryTestFiles();
159 }
160 
TEST(StorageManagerTest,AppendConfigReportTest2)161 TEST(StorageManagerTest, AppendConfigReportTest2) {
162     EXPECT_TRUE(prepareLocalHistoryTestFiles());
163 
164     ProtoOutputStream out;
165     StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, true /*erase?*/,
166                                               false /*isAdb?*/);
167 
168     EXPECT_FALSE(fileExist(file1));
169     EXPECT_FALSE(fileExist(file2));
170     EXPECT_FALSE(fileExist(file1_history));
171     EXPECT_FALSE(fileExist(file2_history));
172 
173     clearLocalHistoryTestFiles();
174 }
175 
TEST(StorageManagerTest,AppendConfigReportTest3)176 TEST(StorageManagerTest, AppendConfigReportTest3) {
177     EXPECT_TRUE(prepareLocalHistoryTestFiles());
178 
179     ProtoOutputStream out;
180     StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, false /*erase?*/,
181                                               true /*isAdb?*/);
182 
183     EXPECT_TRUE(fileExist(file1));
184     EXPECT_TRUE(fileExist(file2));
185     EXPECT_FALSE(fileExist(file1_history));
186     EXPECT_FALSE(fileExist(file2_history));
187 
188     clearLocalHistoryTestFiles();
189 }
190 
TEST(StorageManagerTest,AppendConfigReportTest4)191 TEST(StorageManagerTest, AppendConfigReportTest4) {
192     EXPECT_TRUE(prepareLocalHistoryTestFiles());
193 
194     ProtoOutputStream out;
195     StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, true /*erase?*/,
196                                               true /*isAdb?*/);
197 
198     EXPECT_FALSE(fileExist(file1));
199     EXPECT_FALSE(fileExist(file2));
200     EXPECT_FALSE(fileExist(file1_history));
201     EXPECT_FALSE(fileExist(file2_history));
202 
203     clearLocalHistoryTestFiles();
204 }
205 
TEST(StorageManagerTest,TrainInfoReadWrite32To64BitTest)206 TEST(StorageManagerTest, TrainInfoReadWrite32To64BitTest) {
207     InstallTrainInfo trainInfo;
208     trainInfo.trainVersionCode = 12345;
209     trainInfo.trainName = "This is a train name #)$(&&$";
210     trainInfo.status = 1;
211     const char* expIds = "test_ids";
212     trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
213 
214     // Write the train info. fork the code to always write in 32 bit.
215     StorageManager::deleteSuffixedFiles(TRAIN_INFO_DIR, trainInfo.trainName.c_str());
216     std::string fileName = base::StringPrintf("%s/%ld_%s", TRAIN_INFO_DIR, (long)getWallClockSec(),
217                                               trainInfo.trainName.c_str());
218 
219     int fd = open(fileName.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
220     ASSERT_NE(fd, -1);
221 
222     size_t result;
223     // Write the magic word
224     result = write(fd, &TRAIN_INFO_FILE_MAGIC, sizeof(TRAIN_INFO_FILE_MAGIC));
225     ASSERT_EQ(result, sizeof(TRAIN_INFO_FILE_MAGIC));
226 
227     // Write the train version
228     const size_t trainVersionCodeByteCount = sizeof(trainInfo.trainVersionCode);
229     result = write(fd, &trainInfo.trainVersionCode, trainVersionCodeByteCount);
230     ASSERT_EQ(result, trainVersionCodeByteCount);
231 
232     // Write # of bytes in trainName to file.
233     // NB: this is changed from size_t to int32_t for this test.
234     const int32_t trainNameSize = trainInfo.trainName.size();
235     const size_t trainNameSizeByteCount = sizeof(trainNameSize);
236     result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount);
237     ASSERT_EQ(result, trainNameSizeByteCount);
238 
239     // Write trainName to file
240     result = write(fd, trainInfo.trainName.c_str(), trainNameSize);
241     ASSERT_EQ(result, trainNameSize);
242 
243     // Write status to file
244     const size_t statusByteCount = sizeof(trainInfo.status);
245     result = write(fd, (uint8_t*)&trainInfo.status, statusByteCount);
246     ASSERT_EQ(result, statusByteCount);
247 
248     // Write experiment id count to file.
249     // NB: this is changed from size_t to int32_t for this test.
250     const int32_t experimentIdsCount = trainInfo.experimentIds.size();
251     const size_t experimentIdsCountByteCount = sizeof(experimentIdsCount);
252     result = write(fd, (uint8_t*)&experimentIdsCount, experimentIdsCountByteCount);
253     ASSERT_EQ(result, experimentIdsCountByteCount);
254 
255     // Write experimentIds to file
256     for (size_t i = 0; i < experimentIdsCount; i++) {
257         const int64_t experimentId = trainInfo.experimentIds[i];
258         const size_t experimentIdByteCount = sizeof(experimentId);
259         result = write(fd, &experimentId, experimentIdByteCount);
260         ASSERT_EQ(result, experimentIdByteCount);
261     }
262 
263     // Write bools to file
264     const size_t boolByteCount = sizeof(trainInfo.requiresStaging);
265     result = write(fd, (uint8_t*)&trainInfo.requiresStaging, boolByteCount);
266     ASSERT_EQ(result, boolByteCount);
267     result = write(fd, (uint8_t*)&trainInfo.rollbackEnabled, boolByteCount);
268     ASSERT_EQ(result, boolByteCount);
269     result = write(fd, (uint8_t*)&trainInfo.requiresLowLatencyMonitor, boolByteCount);
270     ASSERT_EQ(result, boolByteCount);
271     close(fd);
272 
273     InstallTrainInfo trainInfoResult;
274     EXPECT_TRUE(StorageManager::readTrainInfo(trainInfo.trainName, trainInfoResult));
275 
276     EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
277     ASSERT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
278     EXPECT_EQ(trainInfo.trainName, trainInfoResult.trainName);
279     EXPECT_EQ(trainInfo.status, trainInfoResult.status);
280     ASSERT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
281     EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
282 }
283 
TEST(StorageManagerTest,DeleteUnmodifiedOldDbFiles)284 TEST(StorageManagerTest, DeleteUnmodifiedOldDbFiles) {
285     if (!isAtLeastU()) {
286         GTEST_SKIP();
287     }
288     ConfigKey key(123, 12345);
289     unique_ptr<LogEvent> event = CreateRestrictedLogEvent(/*atomTag=*/10, /*timestampNs=*/1000);
290     dbutils::createTableIfNeeded(key, /*metricId=*/1, *event);
291     EXPECT_TRUE(StorageManager::hasFile(
292             base::StringPrintf("%s/%s", STATS_RESTRICTED_DATA_DIR, "123_12345.db").c_str()));
293 
294     int64_t wallClockSec = getWallClockSec() + (StatsdStats::kMaxAgeSecond + 1);
295     StorageManager::enforceDbGuardrails(STATS_RESTRICTED_DATA_DIR, wallClockSec,
296                                         /*maxBytes=*/INT_MAX);
297 
298     EXPECT_FALSE(StorageManager::hasFile(
299             base::StringPrintf("%s/%s", STATS_RESTRICTED_DATA_DIR, "123_12345.db").c_str()));
300 }
301 
TEST(StorageManagerTest,DeleteLargeDbFiles)302 TEST(StorageManagerTest, DeleteLargeDbFiles) {
303     if (!isAtLeastU()) {
304         GTEST_SKIP();
305     }
306     ConfigKey key(123, 12345);
307     unique_ptr<LogEvent> event = CreateRestrictedLogEvent(/*atomTag=*/10, /*timestampNs=*/1000);
308     dbutils::createTableIfNeeded(key, /*metricId=*/1, *event);
309     EXPECT_TRUE(StorageManager::hasFile(
310             base::StringPrintf("%s/%s", STATS_RESTRICTED_DATA_DIR, "123_12345.db").c_str()));
311 
312     StorageManager::enforceDbGuardrails(STATS_RESTRICTED_DATA_DIR,
313                                         /*wallClockSec=*/getWallClockSec(),
314                                         /*maxBytes=*/0);
315 
316     EXPECT_FALSE(StorageManager::hasFile(
317             base::StringPrintf("%s/%s", STATS_RESTRICTED_DATA_DIR, "123_12345.db").c_str()));
318 }
319 
320 }  // namespace statsd
321 }  // namespace os
322 }  // namespace android
323 #else
324 GTEST_LOG_(INFO) << "This test does nothing.\n";
325 #endif
326