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, ×); 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 static_cast<int64_t>(buf.f_bavail) * buf.f_frsize; 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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