blob: 50a47d26193ef2a453fe3ec20c575908b28fd22b [file] [log] [blame]
Jeff Sharkey871a8f22017-02-21 18:30:28 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#include <sys/statvfs.h>
20#include <sys/xattr.h>
21
22#include <android-base/logging.h>
23#include <android-base/stringprintf.h>
24#include <cutils/properties.h>
25#include <gtest/gtest.h>
26
27#include "InstalldNativeService.h"
28#include "globals.h"
29#include "utils.h"
30
31using android::base::StringPrintf;
32
33namespace android {
34namespace installd {
35
36constexpr const char* kTestUuid = "TEST";
37
38constexpr int64_t kKbInBytes = 1024;
39constexpr int64_t kMbInBytes = 1024 * kKbInBytes;
40constexpr int64_t kGbInBytes = 1024 * kMbInBytes;
41constexpr int64_t kTbInBytes = 1024 * kGbInBytes;
42
43static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
44static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
45
46int get_property(const char *key, char *value, const char *default_value) {
47 return property_get(key, value, default_value);
48}
49
50bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
51 const char *oat_dir ATTRIBUTE_UNUSED,
52 const char *apk_path ATTRIBUTE_UNUSED,
53 const char *instruction_set ATTRIBUTE_UNUSED) {
54 return false;
55}
56
57bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
58 const char *apk_path ATTRIBUTE_UNUSED,
59 const char *instruction_set ATTRIBUTE_UNUSED) {
60 return false;
61}
62
63bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
64 const char *src ATTRIBUTE_UNUSED,
65 const char *instruction_set ATTRIBUTE_UNUSED) {
66 return false;
67}
68
69static void mkdir(const char* path) {
70 const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
71 ::mkdir(fullPath, 0755);
72}
73
74static void touch(const char* path, int len, int time) {
75 const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
76 int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644);
77 ::fallocate(fd, 0, 0, len);
78 ::close(fd);
79 struct utimbuf times;
80 times.actime = times.modtime = std::time(0) + time;
81 ::utime(fullPath, &times);
82}
83
84static int exists(const char* path) {
85 const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
86 return ::access(fullPath, F_OK);
87}
88
89static int64_t size(const char* path) {
90 const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
91 struct stat buf;
92 if (!stat(fullPath, &buf)) {
93 return buf.st_size;
94 } else {
95 return -1;
96 }
97}
98
99static int64_t free() {
100 struct statvfs buf;
101 if (!statvfs("/data/local/tmp", &buf)) {
102 return buf.f_bavail * buf.f_bsize;
103 } else {
104 return -1;
105 }
106}
107
108static void setxattr(const char* path, const char* key) {
109 const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
110 ::setxattr(fullPath, key, "", 0, 0);
111}
112
113class CacheTest : public testing::Test {
114protected:
115 InstalldNativeService* service;
116 std::unique_ptr<std::string> testUuid;
117
118 virtual void SetUp() {
119 setenv("ANDROID_LOG_TAGS", "*:v", 1);
120 android::base::InitLogging(nullptr);
121
122 service = new InstalldNativeService();
123 testUuid = std::make_unique<std::string>();
124 *testUuid = std::string(kTestUuid);
125 system("mkdir -p /data/local/tmp/user/0");
126 }
127
128 virtual void TearDown() {
129 delete service;
130 system("rm -rf /data/local/tmp/user");
131 }
132};
133
134TEST_F(CacheTest, FreeCache_All) {
135 mkdir("com.example");
136 touch("com.example/normal", 1 * kMbInBytes, 60);
137 mkdir("com.example/cache");
138 mkdir("com.example/cache/foo");
139 touch("com.example/cache/foo/one", 1 * kMbInBytes, 60);
140 touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
141
142 EXPECT_EQ(0, exists("com.example/normal"));
143 EXPECT_EQ(0, exists("com.example/cache/foo/one"));
144 EXPECT_EQ(0, exists("com.example/cache/foo/two"));
145
146 service->freeCache(testUuid, kTbInBytes,
147 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
148
149 EXPECT_EQ(0, exists("com.example/normal"));
150 EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
151 EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
152}
153
154TEST_F(CacheTest, FreeCache_Age) {
155 mkdir("com.example");
156 mkdir("com.example/cache");
157 mkdir("com.example/cache/foo");
158 touch("com.example/cache/foo/one", kMbInBytes, 60);
159 touch("com.example/cache/foo/two", kMbInBytes, 120);
160
161 service->freeCache(testUuid, free() + kKbInBytes,
162 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
163
164 EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
165 EXPECT_EQ(0, exists("com.example/cache/foo/two"));
166
167 service->freeCache(testUuid, free() + kKbInBytes,
168 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
169
170 EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
171 EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
172}
173
174TEST_F(CacheTest, FreeCache_Tombstone) {
175 mkdir("com.example");
176 mkdir("com.example/cache");
177 mkdir("com.example/cache/foo");
178 touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
179 touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 60);
180 mkdir("com.example/cache/bar");
181 touch("com.example/cache/bar/bar1", 2 * kMbInBytes, 120);
182 touch("com.example/cache/bar/bar2", 2 * kMbInBytes, 120);
183
184 setxattr("com.example/cache/bar", "user.cache_tombstone");
185
186 EXPECT_EQ(0, exists("com.example/cache/foo/foo1"));
187 EXPECT_EQ(0, exists("com.example/cache/foo/foo2"));
188 EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
189 EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
190 EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
191 EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
192
193 service->freeCache(testUuid, kTbInBytes,
194 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
195
196 EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
197 EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
198 EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
199 EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
200 EXPECT_EQ(0, size("com.example/cache/bar/bar1"));
201 EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
202}
203
204TEST_F(CacheTest, FreeCache_Atomic) {
205 mkdir("com.example");
206 mkdir("com.example/cache");
207 mkdir("com.example/cache/foo");
208 touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
209 touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
210
211 setxattr("com.example/cache/foo", "user.cache_atomic");
212
213 service->freeCache(testUuid, free() + kKbInBytes,
214 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
215
216 EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
217 EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
218}
219
220TEST_F(CacheTest, FreeCache_AtomicTombstone) {
221 LOG(INFO) << "FreeCache_AtomicTombstone";
222
223 mkdir("com.example");
224 mkdir("com.example/cache");
225
226 // this dir must look really old for some reason?
227 mkdir("com.example/cache/atomic");
228 touch("com.example/cache/atomic/file1", kMbInBytes, 120);
229 touch("com.example/cache/atomic/file2", kMbInBytes, 120);
230 mkdir("com.example/cache/atomic/dir");
231 touch("com.example/cache/atomic/dir/file1", kMbInBytes, 120);
232 touch("com.example/cache/atomic/dir/file2", kMbInBytes, 120);
233 mkdir("com.example/cache/atomic/tomb");
234 touch("com.example/cache/atomic/tomb/file1", kMbInBytes, 120);
235 touch("com.example/cache/atomic/tomb/file2", kMbInBytes, 120);
236 mkdir("com.example/cache/atomic/tomb/dir");
237 touch("com.example/cache/atomic/tomb/dir/file1", kMbInBytes, 120);
238 touch("com.example/cache/atomic/tomb/dir/file2", kMbInBytes, 120);
239
240 mkdir("com.example/cache/tomb");
241 touch("com.example/cache/tomb/file1", kMbInBytes, 240);
242 touch("com.example/cache/tomb/file2", kMbInBytes, 240);
243 mkdir("com.example/cache/tomb/dir");
244 touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
245 touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
246 mkdir("com.example/cache/tomb/atomic");
247 touch("com.example/cache/tomb/atomic/file1", kMbInBytes, 60);
248 touch("com.example/cache/tomb/atomic/file2", kMbInBytes, 60);
249 mkdir("com.example/cache/tomb/atomic/dir");
250 touch("com.example/cache/tomb/atomic/dir/file1", kMbInBytes, 60);
251 touch("com.example/cache/tomb/atomic/dir/file2", kMbInBytes, 60);
252
253 setxattr("com.example/cache/atomic", "user.cache_atomic");
254 setxattr("com.example/cache/atomic/tomb", "user.cache_tombstone");
255 setxattr("com.example/cache/tomb", "user.cache_tombstone");
256 setxattr("com.example/cache/tomb/atomic", "user.cache_atomic");
257
258 service->freeCache(testUuid, free() + kKbInBytes,
259 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
260
261 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file1"));
262 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file2"));
263 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file1"));
264 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file2"));
265 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file1"));
266 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file2"));
267 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file1"));
268 EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file2"));
269
270 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
271 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
272 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
273 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
274 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
275 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
276 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
277 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
278
279 service->freeCache(testUuid, free() + kKbInBytes,
280 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
281
282 EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
283 EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
284 EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
285 EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
286 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
287 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
288 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
289 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
290
291 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
292 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
293 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
294 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
295 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
296 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
297 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
298 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
299
300 service->freeCache(testUuid, kTbInBytes,
301 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
302
303 EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
304 EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
305 EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
306 EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
307 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
308 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
309 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
310 EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
311
312 EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
313 EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
314 EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
315 EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
316 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
317 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
318 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
319 EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
320}
321
322} // namespace installd
323} // namespace android