installd_cache_test.cpp revision ed909ae8db2f44ce7fe7003c6fee457f13669702
1/*
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        PLOG(ERROR) << "Failed to statvfs";
105        return -1;
106    }
107}
108
109static void setxattr(const char* path, const char* key) {
110    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
111    ::setxattr(fullPath, key, "", 0, 0);
112}
113
114class CacheTest : public testing::Test {
115protected:
116    InstalldNativeService* service;
117    std::unique_ptr<std::string> testUuid;
118
119    virtual void SetUp() {
120        setenv("ANDROID_LOG_TAGS", "*:v", 1);
121        android::base::InitLogging(nullptr);
122
123        service = new InstalldNativeService();
124        testUuid = std::make_unique<std::string>();
125        *testUuid = std::string(kTestUuid);
126        system("mkdir -p /data/local/tmp/user/0");
127    }
128
129    virtual void TearDown() {
130        delete service;
131        system("rm -rf /data/local/tmp/user");
132    }
133};
134
135TEST_F(CacheTest, FreeCache_All) {
136    LOG(INFO) << "FreeCache_All";
137
138    mkdir("com.example");
139    touch("com.example/normal", 1 * kMbInBytes, 60);
140    mkdir("com.example/cache");
141    mkdir("com.example/cache/foo");
142    touch("com.example/cache/foo/one", 1 * kMbInBytes, 60);
143    touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
144
145    EXPECT_EQ(0, exists("com.example/normal"));
146    EXPECT_EQ(0, exists("com.example/cache/foo/one"));
147    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
148
149    service->freeCache(testUuid, kTbInBytes,
150            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
151
152    EXPECT_EQ(0, exists("com.example/normal"));
153    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
154    EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
155}
156
157TEST_F(CacheTest, FreeCache_Age) {
158    LOG(INFO) << "FreeCache_Age";
159
160    mkdir("com.example");
161    mkdir("com.example/cache");
162    mkdir("com.example/cache/foo");
163    touch("com.example/cache/foo/one", kMbInBytes, 60);
164    touch("com.example/cache/foo/two", kMbInBytes, 120);
165
166    service->freeCache(testUuid, free() + kKbInBytes,
167            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
168
169    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
170    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
171
172    service->freeCache(testUuid, free() + kKbInBytes,
173            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
174
175    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
176    EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
177}
178
179TEST_F(CacheTest, FreeCache_Tombstone) {
180    LOG(INFO) << "FreeCache_Tombstone";
181
182    mkdir("com.example");
183    mkdir("com.example/cache");
184    mkdir("com.example/cache/foo");
185    touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
186    touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 60);
187    mkdir("com.example/cache/bar");
188    touch("com.example/cache/bar/bar1", 2 * kMbInBytes, 120);
189    touch("com.example/cache/bar/bar2", 2 * kMbInBytes, 120);
190
191    setxattr("com.example/cache/bar", "user.cache_tombstone");
192
193    EXPECT_EQ(0, exists("com.example/cache/foo/foo1"));
194    EXPECT_EQ(0, exists("com.example/cache/foo/foo2"));
195    EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
196    EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
197    EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
198    EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
199
200    service->freeCache(testUuid, kTbInBytes,
201            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
202
203    EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
204    EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
205    EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
206    EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
207    EXPECT_EQ(0, size("com.example/cache/bar/bar1"));
208    EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
209}
210
211TEST_F(CacheTest, FreeCache_Group) {
212    LOG(INFO) << "FreeCache_Group";
213
214    mkdir("com.example");
215    mkdir("com.example/cache");
216    mkdir("com.example/cache/foo");
217    touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
218    touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
219
220    setxattr("com.example/cache/foo", "user.cache_group");
221
222    service->freeCache(testUuid, free() + kKbInBytes,
223            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
224
225    EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
226    EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
227}
228
229TEST_F(CacheTest, FreeCache_GroupTombstone) {
230    LOG(INFO) << "FreeCache_GroupTombstone";
231
232    mkdir("com.example");
233    mkdir("com.example/cache");
234
235    // this dir must look really old for some reason?
236    mkdir("com.example/cache/group");
237    touch("com.example/cache/group/file1", kMbInBytes, 120);
238    touch("com.example/cache/group/file2", kMbInBytes, 120);
239    mkdir("com.example/cache/group/dir");
240    touch("com.example/cache/group/dir/file1", kMbInBytes, 120);
241    touch("com.example/cache/group/dir/file2", kMbInBytes, 120);
242    mkdir("com.example/cache/group/tomb");
243    touch("com.example/cache/group/tomb/file1", kMbInBytes, 120);
244    touch("com.example/cache/group/tomb/file2", kMbInBytes, 120);
245    mkdir("com.example/cache/group/tomb/dir");
246    touch("com.example/cache/group/tomb/dir/file1", kMbInBytes, 120);
247    touch("com.example/cache/group/tomb/dir/file2", kMbInBytes, 120);
248
249    mkdir("com.example/cache/tomb");
250    touch("com.example/cache/tomb/file1", kMbInBytes, 240);
251    touch("com.example/cache/tomb/file2", kMbInBytes, 240);
252    mkdir("com.example/cache/tomb/dir");
253    touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
254    touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
255    mkdir("com.example/cache/tomb/group");
256    touch("com.example/cache/tomb/group/file1", kMbInBytes, 60);
257    touch("com.example/cache/tomb/group/file2", kMbInBytes, 60);
258    mkdir("com.example/cache/tomb/group/dir");
259    touch("com.example/cache/tomb/group/dir/file1", kMbInBytes, 60);
260    touch("com.example/cache/tomb/group/dir/file2", kMbInBytes, 60);
261
262    setxattr("com.example/cache/group", "user.cache_group");
263    setxattr("com.example/cache/group/tomb", "user.cache_tombstone");
264    setxattr("com.example/cache/tomb", "user.cache_tombstone");
265    setxattr("com.example/cache/tomb/group", "user.cache_group");
266
267    service->freeCache(testUuid, free() + kKbInBytes,
268            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
269
270    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
271    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file2"));
272    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file1"));
273    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file2"));
274    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file1"));
275    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file2"));
276    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file1"));
277    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file2"));
278
279    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
280    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
281    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
282    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
283    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
284    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
285    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
286    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
287
288    service->freeCache(testUuid, free() + kKbInBytes,
289            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
290
291    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
292    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
293    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
294    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
295    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
296    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
297    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
298    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
299
300    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
301    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
302    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
303    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
304    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
305    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
306    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
307    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
308
309    service->freeCache(testUuid, kTbInBytes,
310            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
311
312    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
313    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
314    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
315    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
316    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
317    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
318    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
319    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
320
321    EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
322    EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
323    EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
324    EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
325    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
326    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
327    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
328    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
329}
330
331}  // namespace installd
332}  // namespace android
333