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 <sstream> 18#include <stdlib.h> 19#include <string.h> 20#include <sys/statvfs.h> 21#include <sys/xattr.h> 22 23#include <android-base/logging.h> 24#include <android-base/stringprintf.h> 25#include <cutils/properties.h> 26#include <gtest/gtest.h> 27 28#include "InstalldNativeService.h" 29#include "dexopt.h" 30#include "globals.h" 31#include "utils.h" 32 33using android::base::StringPrintf; 34 35namespace android { 36namespace installd { 37 38constexpr const char* kTestUuid = "TEST"; 39 40static constexpr int FLAG_FORCE = 1 << 16; 41 42int get_property(const char *key, char *value, const char *default_value) { 43 return property_get(key, value, default_value); 44} 45 46bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, 47 const char *instruction_set) { 48 return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set); 49} 50 51bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path, 52 const char *instruction_set) { 53 return calculate_odex_file_path_default(path, apk_path, instruction_set); 54} 55 56bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) { 57 return create_cache_path_default(path, src, instruction_set); 58} 59 60static std::string get_full_path(const char* path) { 61 return StringPrintf("/data/local/tmp/user/0/%s", path); 62} 63 64static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) { 65 const std::string fullPath = get_full_path(path); 66 ::mkdir(fullPath.c_str(), mode); 67 ::chown(fullPath.c_str(), owner, group); 68 ::chmod(fullPath.c_str(), mode); 69} 70 71static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) { 72 int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode); 73 ::fchown(fd, owner, group); 74 ::fchmod(fd, mode); 75 ::close(fd); 76} 77 78static int stat_gid(const char* path) { 79 struct stat buf; 80 ::stat(get_full_path(path).c_str(), &buf); 81 return buf.st_gid; 82} 83 84static int stat_mode(const char* path) { 85 struct stat buf; 86 ::stat(get_full_path(path).c_str(), &buf); 87 return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); 88} 89 90class ServiceTest : public testing::Test { 91protected: 92 InstalldNativeService* service; 93 std::unique_ptr<std::string> testUuid; 94 95 virtual void SetUp() { 96 setenv("ANDROID_LOG_TAGS", "*:v", 1); 97 android::base::InitLogging(nullptr); 98 99 service = new InstalldNativeService(); 100 testUuid = std::make_unique<std::string>(); 101 *testUuid = std::string(kTestUuid); 102 system("mkdir -p /data/local/tmp/user/0"); 103 104 init_globals_from_data_and_root(); 105 } 106 107 virtual void TearDown() { 108 delete service; 109 system("rm -rf /data/local/tmp/user"); 110 } 111}; 112 113TEST_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 132TEST_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 156TEST_F(ServiceTest, HashSecondaryDex) { 157 LOG(INFO) << "HashSecondaryDex"; 158 159 mkdir("com.example", 10000, 10000, 0700); 160 mkdir("com.example/foo", 10000, 10000, 0700); 161 touch("com.example/foo/file", 10000, 20000, 0700); 162 163 std::vector<uint8_t> result; 164 std::string dexPath = get_full_path("com.example/foo/file"); 165 EXPECT_TRUE(service->hashSecondaryDexFile( 166 dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); 167 168 EXPECT_EQ(result.size(), 32U); 169 170 std::ostringstream output; 171 output << std::hex << std::setfill('0'); 172 for (auto b : result) { 173 output << std::setw(2) << +b; 174 } 175 176 // This is the SHA256 of an empty string (sha256sum /dev/null) 177 EXPECT_EQ(output.str(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); 178} 179 180TEST_F(ServiceTest, HashSecondaryDex_NoSuch) { 181 LOG(INFO) << "HashSecondaryDex_NoSuch"; 182 183 std::vector<uint8_t> result; 184 std::string dexPath = get_full_path("com.example/foo/file"); 185 EXPECT_TRUE(service->hashSecondaryDexFile( 186 dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); 187 188 EXPECT_EQ(result.size(), 0U); 189} 190 191TEST_F(ServiceTest, HashSecondaryDex_Unreadable) { 192 LOG(INFO) << "HashSecondaryDex_Unreadable"; 193 194 mkdir("com.example", 10000, 10000, 0700); 195 mkdir("com.example/foo", 10000, 10000, 0700); 196 touch("com.example/foo/file", 10000, 20000, 0300); 197 198 std::vector<uint8_t> result; 199 std::string dexPath = get_full_path("com.example/foo/file"); 200 EXPECT_TRUE(service->hashSecondaryDexFile( 201 dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); 202 203 EXPECT_EQ(result.size(), 0U); 204} 205 206TEST_F(ServiceTest, HashSecondaryDex_WrongApp) { 207 LOG(INFO) << "HashSecondaryDex_WrongApp"; 208 209 mkdir("com.example", 10000, 10000, 0700); 210 mkdir("com.example/foo", 10000, 10000, 0700); 211 touch("com.example/foo/file", 10000, 20000, 0700); 212 213 std::vector<uint8_t> result; 214 std::string dexPath = get_full_path("com.example/foo/file"); 215 EXPECT_FALSE(service->hashSecondaryDexFile( 216 dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk()); 217} 218 219TEST_F(ServiceTest, CalculateOat) { 220 char buf[PKG_PATH_MAX]; 221 222 EXPECT_TRUE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file.apk", "isa")); 223 EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf)); 224 225 EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file", "isa")); 226 EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "file", "isa")); 227} 228 229TEST_F(ServiceTest, CalculateOdex) { 230 char buf[PKG_PATH_MAX]; 231 232 EXPECT_TRUE(calculate_odex_file_path(buf, "/path/to/file.apk", "isa")); 233 EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf)); 234} 235 236TEST_F(ServiceTest, CalculateCache) { 237 char buf[PKG_PATH_MAX]; 238 239 EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa")); 240 EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf)); 241} 242 243} // namespace installd 244} // namespace android 245