blob: 863cdfe55b35cc2c67ce82cedce07192976dde5a [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
Jeff Sharkey77be8962018-08-29 10:31:25 -060043#define FLAG_FREE_CACHE_V2 InstalldNativeService::FLAG_FREE_CACHE_V2
44#define FLAG_FREE_CACHE_V2_DEFY_QUOTA InstalldNativeService::FLAG_FREE_CACHE_V2_DEFY_QUOTA
Jeff Sharkey871a8f22017-02-21 18:30:28 -070045
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) {
Nick Desaulniersb2c02552019-10-07 21:00:40 -070070 const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
71 ::mkdir(fullPath.c_str(), 0755);
Jeff Sharkey871a8f22017-02-21 18:30:28 -070072}
73
74static void touch(const char* path, int len, int time) {
Nick Desaulniersb2c02552019-10-07 21:00:40 -070075 const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
76 int fd = ::open(fullPath.c_str(), O_RDWR | O_CREAT, 0644);
Jeff Sharkey871a8f22017-02-21 18:30:28 -070077 ::fallocate(fd, 0, 0, len);
78 ::close(fd);
79 struct utimbuf times;
80 times.actime = times.modtime = std::time(0) + time;
Nick Desaulniersb2c02552019-10-07 21:00:40 -070081 ::utime(fullPath.c_str(), &times);
Jeff Sharkey871a8f22017-02-21 18:30:28 -070082}
83
84static int exists(const char* path) {
Nick Desaulniersb2c02552019-10-07 21:00:40 -070085 const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
86 return ::access(fullPath.c_str(), F_OK);
Jeff Sharkey871a8f22017-02-21 18:30:28 -070087}
88
89static int64_t size(const char* path) {
Nick Desaulniersb2c02552019-10-07 21:00:40 -070090 const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
Jeff Sharkey871a8f22017-02-21 18:30:28 -070091 struct stat buf;
Nick Desaulniersb2c02552019-10-07 21:00:40 -070092 if (!stat(fullPath.c_str(), &buf)) {
Jeff Sharkey871a8f22017-02-21 18:30:28 -070093 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)) {
Jeff Sharkeybdd4de82017-08-11 15:13:31 -0600102 return static_cast<int64_t>(buf.f_bavail) * buf.f_frsize;
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700103 } else {
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600104 PLOG(ERROR) << "Failed to statvfs";
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700105 return -1;
106 }
107}
108
109static void setxattr(const char* path, const char* key) {
Nick Desaulniersb2c02552019-10-07 21:00:40 -0700110 const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
111 ::setxattr(fullPath.c_str(), key, "", 0, 0);
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700112}
113
114class CacheTest : public testing::Test {
115protected:
116 InstalldNativeService* service;
Jooyung Han2d5878e2020-01-23 12:45:10 +0900117 std::optional<std::string> testUuid;
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700118
119 virtual void SetUp() {
120 setenv("ANDROID_LOG_TAGS", "*:v", 1);
121 android::base::InitLogging(nullptr);
122
123 service = new InstalldNativeService();
Jooyung Han2d5878e2020-01-23 12:45:10 +0900124 testUuid = kTestUuid;
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700125 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) {
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600135 LOG(INFO) << "FreeCache_All";
136
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700137 mkdir("com.example");
138 touch("com.example/normal", 1 * kMbInBytes, 60);
139 mkdir("com.example/cache");
140 mkdir("com.example/cache/foo");
141 touch("com.example/cache/foo/one", 1 * kMbInBytes, 60);
142 touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
143
144 EXPECT_EQ(0, exists("com.example/normal"));
145 EXPECT_EQ(0, exists("com.example/cache/foo/one"));
146 EXPECT_EQ(0, exists("com.example/cache/foo/two"));
147
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600148 service->freeCache(testUuid, kTbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700149 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
150
151 EXPECT_EQ(0, exists("com.example/normal"));
152 EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
153 EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
154}
155
156TEST_F(CacheTest, FreeCache_Age) {
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600157 LOG(INFO) << "FreeCache_Age";
158
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700159 mkdir("com.example");
160 mkdir("com.example/cache");
161 mkdir("com.example/cache/foo");
162 touch("com.example/cache/foo/one", kMbInBytes, 60);
163 touch("com.example/cache/foo/two", kMbInBytes, 120);
164
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600165 service->freeCache(testUuid, free() + kKbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700166 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
167
168 EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
169 EXPECT_EQ(0, exists("com.example/cache/foo/two"));
170
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600171 service->freeCache(testUuid, free() + kKbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700172 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
173
174 EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
175 EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
176}
177
178TEST_F(CacheTest, FreeCache_Tombstone) {
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600179 LOG(INFO) << "FreeCache_Tombstone";
180
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700181 mkdir("com.example");
182 mkdir("com.example/cache");
183 mkdir("com.example/cache/foo");
184 touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
185 touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 60);
186 mkdir("com.example/cache/bar");
187 touch("com.example/cache/bar/bar1", 2 * kMbInBytes, 120);
188 touch("com.example/cache/bar/bar2", 2 * kMbInBytes, 120);
189
190 setxattr("com.example/cache/bar", "user.cache_tombstone");
191
192 EXPECT_EQ(0, exists("com.example/cache/foo/foo1"));
193 EXPECT_EQ(0, exists("com.example/cache/foo/foo2"));
194 EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
195 EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
196 EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
197 EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
198
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600199 service->freeCache(testUuid, kTbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700200 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
201
202 EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
203 EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
204 EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
205 EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
206 EXPECT_EQ(0, size("com.example/cache/bar/bar1"));
207 EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
208}
209
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600210TEST_F(CacheTest, FreeCache_Group) {
211 LOG(INFO) << "FreeCache_Group";
212
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700213 mkdir("com.example");
214 mkdir("com.example/cache");
215 mkdir("com.example/cache/foo");
216 touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
217 touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
218
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600219 setxattr("com.example/cache/foo", "user.cache_group");
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700220
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600221 service->freeCache(testUuid, free() + kKbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700222 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
223
224 EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
225 EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
226}
227
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600228TEST_F(CacheTest, FreeCache_GroupTombstone) {
229 LOG(INFO) << "FreeCache_GroupTombstone";
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700230
231 mkdir("com.example");
232 mkdir("com.example/cache");
233
234 // this dir must look really old for some reason?
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600235 mkdir("com.example/cache/group");
236 touch("com.example/cache/group/file1", kMbInBytes, 120);
237 touch("com.example/cache/group/file2", kMbInBytes, 120);
238 mkdir("com.example/cache/group/dir");
239 touch("com.example/cache/group/dir/file1", kMbInBytes, 120);
240 touch("com.example/cache/group/dir/file2", kMbInBytes, 120);
241 mkdir("com.example/cache/group/tomb");
242 touch("com.example/cache/group/tomb/file1", kMbInBytes, 120);
243 touch("com.example/cache/group/tomb/file2", kMbInBytes, 120);
244 mkdir("com.example/cache/group/tomb/dir");
245 touch("com.example/cache/group/tomb/dir/file1", kMbInBytes, 120);
246 touch("com.example/cache/group/tomb/dir/file2", kMbInBytes, 120);
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700247
248 mkdir("com.example/cache/tomb");
249 touch("com.example/cache/tomb/file1", kMbInBytes, 240);
250 touch("com.example/cache/tomb/file2", kMbInBytes, 240);
251 mkdir("com.example/cache/tomb/dir");
252 touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
253 touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600254 mkdir("com.example/cache/tomb/group");
255 touch("com.example/cache/tomb/group/file1", kMbInBytes, 60);
256 touch("com.example/cache/tomb/group/file2", kMbInBytes, 60);
257 mkdir("com.example/cache/tomb/group/dir");
258 touch("com.example/cache/tomb/group/dir/file1", kMbInBytes, 60);
259 touch("com.example/cache/tomb/group/dir/file2", kMbInBytes, 60);
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700260
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600261 setxattr("com.example/cache/group", "user.cache_group");
262 setxattr("com.example/cache/group/tomb", "user.cache_tombstone");
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700263 setxattr("com.example/cache/tomb", "user.cache_tombstone");
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600264 setxattr("com.example/cache/tomb/group", "user.cache_group");
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700265
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600266 service->freeCache(testUuid, free() + kKbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700267 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
268
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600269 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
270 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file2"));
271 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file1"));
272 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file2"));
273 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file1"));
274 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file2"));
275 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file1"));
276 EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file2"));
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700277
278 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
279 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
280 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
281 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600282 EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
283 EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
284 EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
285 EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700286
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600287 service->freeCache(testUuid, free() + kKbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700288 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
289
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600290 EXPECT_EQ(-1, size("com.example/cache/group/file1"));
291 EXPECT_EQ(-1, size("com.example/cache/group/file2"));
292 EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
293 EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
294 EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
295 EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
296 EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
297 EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700298
299 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
300 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
301 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
302 EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600303 EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
304 EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
305 EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
306 EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700307
Jeff Sharkey60f8a532017-05-30 14:38:42 -0600308 service->freeCache(testUuid, kTbInBytes, 0,
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700309 FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
310
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600311 EXPECT_EQ(-1, size("com.example/cache/group/file1"));
312 EXPECT_EQ(-1, size("com.example/cache/group/file2"));
313 EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
314 EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
315 EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
316 EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
317 EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
318 EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700319
320 EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
321 EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
322 EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
323 EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
Jeff Sharkeyed909ae2017-03-22 21:27:40 -0600324 EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
325 EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
326 EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
327 EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
Jeff Sharkey871a8f22017-02-21 18:30:28 -0700328}
329
330} // namespace installd
331} // namespace android