• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 using android::base::StringPrintf;
32 
33 namespace android {
34 namespace installd {
35 
36 constexpr const char* kTestUuid = "TEST";
37 
38 constexpr int64_t kKbInBytes = 1024;
39 constexpr int64_t kMbInBytes = 1024 * kKbInBytes;
40 constexpr int64_t kGbInBytes = 1024 * kMbInBytes;
41 constexpr int64_t kTbInBytes = 1024 * kGbInBytes;
42 
43 #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
45 #define FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES InstalldNativeService::FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES
46 
get_property(const char * key,char * value,const char * default_value)47 int get_property(const char *key, char *value, const char *default_value) {
48     return property_get(key, value, default_value);
49 }
50 
calculate_oat_file_path(char path[PKG_PATH_MAX]ATTRIBUTE_UNUSED,const char * oat_dir ATTRIBUTE_UNUSED,const char * apk_path ATTRIBUTE_UNUSED,const char * instruction_set ATTRIBUTE_UNUSED)51 bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
52         const char *oat_dir ATTRIBUTE_UNUSED,
53         const char *apk_path ATTRIBUTE_UNUSED,
54         const char *instruction_set ATTRIBUTE_UNUSED) {
55     return false;
56 }
57 
calculate_odex_file_path(char path[PKG_PATH_MAX]ATTRIBUTE_UNUSED,const char * apk_path ATTRIBUTE_UNUSED,const char * instruction_set ATTRIBUTE_UNUSED)58 bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
59         const char *apk_path ATTRIBUTE_UNUSED,
60         const char *instruction_set ATTRIBUTE_UNUSED) {
61     return false;
62 }
63 
create_cache_path(char path[PKG_PATH_MAX]ATTRIBUTE_UNUSED,const char * src ATTRIBUTE_UNUSED,const char * instruction_set ATTRIBUTE_UNUSED)64 bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
65         const char *src ATTRIBUTE_UNUSED,
66         const char *instruction_set ATTRIBUTE_UNUSED) {
67     return false;
68 }
69 
mkdir(const char * path)70 static void mkdir(const char* path) {
71     const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
72     ::mkdir(fullPath.c_str(), 0755);
73 }
74 
touch(const char * path,int len,int time)75 static void touch(const char* path, int len, int time) {
76     const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
77     int fd = ::open(fullPath.c_str(), O_RDWR | O_CREAT, 0644);
78     ::fallocate(fd, 0, 0, len);
79     ::close(fd);
80     struct utimbuf times;
81     times.actime = times.modtime = std::time(0) + time;
82     ::utime(fullPath.c_str(), &times);
83 }
84 
exists(const char * path)85 static int exists(const char* path) {
86     const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
87     return ::access(fullPath.c_str(), F_OK);
88 }
89 
size(const char * path)90 static int64_t size(const char* path) {
91     const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
92     struct stat buf;
93     if (!stat(fullPath.c_str(), &buf)) {
94         return buf.st_size;
95     } else {
96         return -1;
97     }
98 }
99 
free()100 static int64_t free() {
101     struct statvfs buf;
102     if (!statvfs("/data/local/tmp", &buf)) {
103         return static_cast<int64_t>(buf.f_bavail) * buf.f_frsize;
104     } else {
105         PLOG(ERROR) << "Failed to statvfs";
106         return -1;
107     }
108 }
109 
setxattr(const char * path,const char * key)110 static void setxattr(const char* path, const char* key) {
111     const std::string fullPath = StringPrintf("/data/local/tmp/user/0/%s", path);
112     ::setxattr(fullPath.c_str(), key, "", 0, 0);
113 }
114 
115 class CacheTest : public testing::Test {
116 protected:
117     InstalldNativeService* service;
118     std::optional<std::string> testUuid;
119 
SetUp()120     virtual void SetUp() {
121         setenv("ANDROID_LOG_TAGS", "*:v", 1);
122         android::base::InitLogging(nullptr);
123 
124         service = new InstalldNativeService();
125         testUuid = kTestUuid;
126         system("rm -rf /data/local/tmp/user");
127         system("mkdir -p /data/local/tmp/user/0");
128     }
129 
TearDown()130     virtual void TearDown() {
131         delete service;
132         system("rm -rf /data/local/tmp/user");
133     }
134 };
135 
TEST_F(CacheTest,FreeCache_All)136 TEST_F(CacheTest, FreeCache_All) {
137     LOG(INFO) << "FreeCache_All";
138 
139     mkdir("com.example");
140     touch("com.example/normal", 1 * kMbInBytes, 60);
141     mkdir("com.example/cache");
142     mkdir("com.example/cache/foo");
143     touch("com.example/cache/foo/one", 1 * kMbInBytes, 60);
144     touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
145 
146     EXPECT_EQ(0, exists("com.example/normal"));
147     EXPECT_EQ(0, exists("com.example/cache/foo/one"));
148     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
149 
150     service->freeCache(testUuid, kTbInBytes,
151             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
152 
153     EXPECT_EQ(0, exists("com.example/normal"));
154     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
155     EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
156 }
157 
TEST_F(CacheTest,FreeCache_NonAggressive)158 TEST_F(CacheTest, FreeCache_NonAggressive) {
159     LOG(INFO) << "FreeCache_NonAggressive";
160 
161     mkdir("com.example");
162     touch("com.example/normal", 1 * kMbInBytes, 60);
163     mkdir("com.example/cache");
164     mkdir("com.example/cache/foo");
165     touch("com.example/cache/foo/one", 65 * kMbInBytes, 60);
166     touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
167 
168     EXPECT_EQ(0, exists("com.example/normal"));
169     EXPECT_EQ(0, exists("com.example/cache/foo/one"));
170     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
171 
172     service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2);
173 
174     EXPECT_EQ(0, exists("com.example/normal"));
175     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
176     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
177 
178     service->freeCache(testUuid, kTbInBytes, FLAG_FREE_CACHE_V2);
179 
180     EXPECT_EQ(0, exists("com.example/normal"));
181     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
182     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
183 }
184 
TEST_F(CacheTest,FreeCache_DefyTargetFreeBytes)185 TEST_F(CacheTest, FreeCache_DefyTargetFreeBytes) {
186     LOG(INFO) << "FreeCache_DefyTargetFreeBytes";
187 
188     mkdir("com.example");
189     touch("com.example/normal", 1 * kMbInBytes, 60);
190     mkdir("com.example/cache");
191     mkdir("com.example/cache/foo");
192     touch("com.example/cache/foo/one", 65 * kMbInBytes, 60);
193     touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
194 
195     EXPECT_EQ(0, exists("com.example/normal"));
196     EXPECT_EQ(0, exists("com.example/cache/foo/one"));
197     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
198 
199     service->freeCache(testUuid, kMbInBytes, FLAG_FREE_CACHE_V2
200             | FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
201 
202     EXPECT_EQ(0, exists("com.example/normal"));
203     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
204     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
205 
206     service->freeCache(testUuid, kMbInBytes, FLAG_FREE_CACHE_V2
207             | FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
208 
209     EXPECT_EQ(0, exists("com.example/normal"));
210     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
211     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
212 }
213 
TEST_F(CacheTest,FreeCache_Age)214 TEST_F(CacheTest, FreeCache_Age) {
215     LOG(INFO) << "FreeCache_Age";
216 
217     mkdir("com.example");
218     mkdir("com.example/cache");
219     mkdir("com.example/cache/foo");
220     touch("com.example/cache/foo/one", kMbInBytes, 60);
221     touch("com.example/cache/foo/two", kMbInBytes, 120);
222 
223     service->freeCache(testUuid, free() + kKbInBytes,
224             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
225 
226     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
227     EXPECT_EQ(0, exists("com.example/cache/foo/two"));
228 
229     service->freeCache(testUuid, free() + kKbInBytes,
230             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
231 
232     EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
233     EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
234 }
235 
TEST_F(CacheTest,FreeCache_Tombstone)236 TEST_F(CacheTest, FreeCache_Tombstone) {
237     LOG(INFO) << "FreeCache_Tombstone";
238 
239     mkdir("com.example");
240     mkdir("com.example/cache");
241     mkdir("com.example/cache/foo");
242     touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
243     touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 60);
244     mkdir("com.example/cache/bar");
245     touch("com.example/cache/bar/bar1", 2 * kMbInBytes, 120);
246     touch("com.example/cache/bar/bar2", 2 * kMbInBytes, 120);
247 
248     setxattr("com.example/cache/bar", "user.cache_tombstone");
249 
250     EXPECT_EQ(0, exists("com.example/cache/foo/foo1"));
251     EXPECT_EQ(0, exists("com.example/cache/foo/foo2"));
252     EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
253     EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
254     EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
255     EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
256 
257     service->freeCache(testUuid, kTbInBytes,
258             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
259 
260     EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
261     EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
262     EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
263     EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
264     EXPECT_EQ(0, size("com.example/cache/bar/bar1"));
265     EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
266 }
267 
TEST_F(CacheTest,FreeCache_Group)268 TEST_F(CacheTest, FreeCache_Group) {
269     LOG(INFO) << "FreeCache_Group";
270 
271     mkdir("com.example");
272     mkdir("com.example/cache");
273     mkdir("com.example/cache/foo");
274     touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
275     touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
276 
277     setxattr("com.example/cache/foo", "user.cache_group");
278 
279     service->freeCache(testUuid, free() + kKbInBytes,
280             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
281 
282     EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
283     EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
284 }
285 
TEST_F(CacheTest,FreeCache_GroupTombstone)286 TEST_F(CacheTest, FreeCache_GroupTombstone) {
287     LOG(INFO) << "FreeCache_GroupTombstone";
288 
289     mkdir("com.example");
290     mkdir("com.example/cache");
291 
292     // this dir must look really old for some reason?
293     mkdir("com.example/cache/group");
294     touch("com.example/cache/group/file1", kMbInBytes, 120);
295     touch("com.example/cache/group/file2", kMbInBytes, 120);
296     mkdir("com.example/cache/group/dir");
297     touch("com.example/cache/group/dir/file1", kMbInBytes, 120);
298     touch("com.example/cache/group/dir/file2", kMbInBytes, 120);
299     mkdir("com.example/cache/group/tomb");
300     touch("com.example/cache/group/tomb/file1", kMbInBytes, 120);
301     touch("com.example/cache/group/tomb/file2", kMbInBytes, 120);
302     mkdir("com.example/cache/group/tomb/dir");
303     touch("com.example/cache/group/tomb/dir/file1", kMbInBytes, 120);
304     touch("com.example/cache/group/tomb/dir/file2", kMbInBytes, 120);
305 
306     mkdir("com.example/cache/tomb");
307     touch("com.example/cache/tomb/file1", kMbInBytes, 240);
308     touch("com.example/cache/tomb/file2", kMbInBytes, 240);
309     mkdir("com.example/cache/tomb/dir");
310     touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
311     touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
312     mkdir("com.example/cache/tomb/group");
313     touch("com.example/cache/tomb/group/file1", kMbInBytes, 60);
314     touch("com.example/cache/tomb/group/file2", kMbInBytes, 60);
315     mkdir("com.example/cache/tomb/group/dir");
316     touch("com.example/cache/tomb/group/dir/file1", kMbInBytes, 60);
317     touch("com.example/cache/tomb/group/dir/file2", kMbInBytes, 60);
318 
319     setxattr("com.example/cache/group", "user.cache_group");
320     setxattr("com.example/cache/group/tomb", "user.cache_tombstone");
321     setxattr("com.example/cache/tomb", "user.cache_tombstone");
322     setxattr("com.example/cache/tomb/group", "user.cache_group");
323 
324     service->freeCache(testUuid, free() + kKbInBytes,
325             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
326 
327     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
328     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file2"));
329     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file1"));
330     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file2"));
331     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file1"));
332     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file2"));
333     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file1"));
334     EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file2"));
335 
336     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
337     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
338     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
339     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
340     EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
341     EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
342     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
343     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
344 
345     service->freeCache(testUuid, free() + kKbInBytes,
346             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
347 
348     EXPECT_EQ(-1, size("com.example/cache/group/file1"));
349     EXPECT_EQ(-1, size("com.example/cache/group/file2"));
350     EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
351     EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
352     EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
353     EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
354     EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
355     EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
356 
357     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
358     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
359     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
360     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
361     EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
362     EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
363     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
364     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
365 
366     service->freeCache(testUuid, kTbInBytes,
367             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
368 
369     EXPECT_EQ(-1, size("com.example/cache/group/file1"));
370     EXPECT_EQ(-1, size("com.example/cache/group/file2"));
371     EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
372     EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
373     EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
374     EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
375     EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
376     EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
377 
378     EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
379     EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
380     EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
381     EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
382     EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
383     EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
384     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
385     EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
386 }
387 
388 }  // namespace installd
389 }  // namespace android
390