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