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 static constexpr int FLAG_FORCE = 1 << 16; 39 40 int get_property(const char *key, char *value, const char *default_value) { 41 return property_get(key, value, default_value); 42 } 43 44 bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED, 45 const char *oat_dir ATTRIBUTE_UNUSED, 46 const char *apk_path ATTRIBUTE_UNUSED, 47 const char *instruction_set ATTRIBUTE_UNUSED) { 48 return false; 49 } 50 51 bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED, 52 const char *apk_path ATTRIBUTE_UNUSED, 53 const char *instruction_set ATTRIBUTE_UNUSED) { 54 return false; 55 } 56 57 bool create_cache_path(char path[PKG_PATH_MAX], 58 const char *src, 59 const char *instruction_set) { 60 // Not really a valid path but it's good enough for testing. 61 sprintf(path,"/data/dalvik-cache/%s/%s", instruction_set, src); 62 return true; 63 } 64 65 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) { 66 const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str(); 67 ::mkdir(fullPath, mode); 68 ::chown(fullPath, owner, group); 69 ::chmod(fullPath, mode); 70 } 71 72 static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) { 73 int fd = ::open(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), 74 O_RDWR | O_CREAT, mode); 75 ::fchown(fd, owner, group); 76 ::fchmod(fd, mode); 77 ::close(fd); 78 } 79 80 static int stat_gid(const char* path) { 81 struct stat buf; 82 ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf); 83 return buf.st_gid; 84 } 85 86 static int stat_mode(const char* path) { 87 struct stat buf; 88 ::stat(StringPrintf("/data/local/tmp/user/0/%s", path).c_str(), &buf); 89 return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); 90 } 91 92 class ServiceTest : public testing::Test { 93 protected: 94 InstalldNativeService* service; 95 std::unique_ptr<std::string> testUuid; 96 97 virtual void SetUp() { 98 setenv("ANDROID_LOG_TAGS", "*:v", 1); 99 android::base::InitLogging(nullptr); 100 101 service = new InstalldNativeService(); 102 testUuid = std::make_unique<std::string>(); 103 *testUuid = std::string(kTestUuid); 104 system("mkdir -p /data/local/tmp/user/0"); 105 } 106 107 virtual void TearDown() { 108 delete service; 109 system("rm -rf /data/local/tmp/user"); 110 } 111 }; 112 113 TEST_F(ServiceTest, FixupAppData_Upgrade) { 114 LOG(INFO) << "FixupAppData_Upgrade"; 115 116 mkdir("com.example", 10000, 10000, 0700); 117 mkdir("com.example/normal", 10000, 10000, 0700); 118 mkdir("com.example/cache", 10000, 10000, 0700); 119 touch("com.example/cache/file", 10000, 10000, 0700); 120 121 service->fixupAppData(testUuid, 0); 122 123 EXPECT_EQ(10000, stat_gid("com.example/normal")); 124 EXPECT_EQ(20000, stat_gid("com.example/cache")); 125 EXPECT_EQ(20000, stat_gid("com.example/cache/file")); 126 127 EXPECT_EQ(0700, stat_mode("com.example/normal")); 128 EXPECT_EQ(02771, stat_mode("com.example/cache")); 129 EXPECT_EQ(0700, stat_mode("com.example/cache/file")); 130 } 131 132 TEST_F(ServiceTest, FixupAppData_Moved) { 133 LOG(INFO) << "FixupAppData_Moved"; 134 135 mkdir("com.example", 10000, 10000, 0700); 136 mkdir("com.example/foo", 10000, 10000, 0700); 137 touch("com.example/foo/file", 10000, 20000, 0700); 138 mkdir("com.example/bar", 10000, 20000, 0700); 139 touch("com.example/bar/file", 10000, 20000, 0700); 140 141 service->fixupAppData(testUuid, 0); 142 143 EXPECT_EQ(10000, stat_gid("com.example/foo")); 144 EXPECT_EQ(20000, stat_gid("com.example/foo/file")); 145 EXPECT_EQ(10000, stat_gid("com.example/bar")); 146 EXPECT_EQ(10000, stat_gid("com.example/bar/file")); 147 148 service->fixupAppData(testUuid, FLAG_FORCE); 149 150 EXPECT_EQ(10000, stat_gid("com.example/foo")); 151 EXPECT_EQ(10000, stat_gid("com.example/foo/file")); 152 EXPECT_EQ(10000, stat_gid("com.example/bar")); 153 EXPECT_EQ(10000, stat_gid("com.example/bar/file")); 154 } 155 156 TEST_F(ServiceTest, RmDexNoDalvikCache) { 157 LOG(INFO) << "RmDexNoDalvikCache"; 158 159 // Try to remove a non existing dalvik cache dex. The call should be 160 // successful because there's nothing to remove. 161 EXPECT_TRUE(service->rmdex("com.example", "arm").isOk()); 162 } 163 164 } // namespace installd 165 } // namespace android 166