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 <string> 18 #include <vector> 19 20 #include <backtrace/BacktraceMap.h> 21 #include <gtest/gtest.h> 22 23 #include "base/file_utils.h" 24 #include "common_runtime_test.h" 25 #include "compiler_callbacks.h" 26 #include "dex2oat_environment_test.h" 27 #include "dexopt_test.h" 28 #include "gc/space/image_space.h" 29 #include "mem_map.h" 30 31 namespace art { 32 void DexoptTest::SetUp() { 33 ReserveImageSpace(); 34 Dex2oatEnvironmentTest::SetUp(); 35 } 36 37 void DexoptTest::PreRuntimeCreate() { 38 std::string error_msg; 39 ASSERT_TRUE(PreRelocateImage(GetImageLocation(), &error_msg)) << error_msg; 40 ASSERT_TRUE(PreRelocateImage(GetImageLocation2(), &error_msg)) << error_msg; 41 UnreserveImageSpace(); 42 } 43 44 void DexoptTest::PostRuntimeCreate() { 45 ReserveImageSpace(); 46 } 47 48 void DexoptTest::GenerateOatForTest(const std::string& dex_location, 49 const std::string& oat_location_in, 50 CompilerFilter::Filter filter, 51 bool relocate, 52 bool pic, 53 bool with_alternate_image, 54 const char* compilation_reason) { 55 std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA)); 56 std::string dalvik_cache_tmp = dalvik_cache + ".redirected"; 57 std::string oat_location = oat_location_in; 58 if (!relocate) { 59 // Temporarily redirect the dalvik cache so dex2oat doesn't find the 60 // relocated image file. 61 ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno); 62 // If the oat location is in dalvik cache, replace the cache path with the temporary one. 63 size_t pos = oat_location.find(dalvik_cache); 64 if (pos != std::string::npos) { 65 oat_location = oat_location.replace(pos, dalvik_cache.length(), dalvik_cache_tmp); 66 } 67 } 68 69 std::vector<std::string> args; 70 args.push_back("--dex-file=" + dex_location); 71 args.push_back("--oat-file=" + oat_location); 72 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter)); 73 args.push_back("--runtime-arg"); 74 75 // Use -Xnorelocate regardless of the relocate argument. 76 // We control relocation by redirecting the dalvik cache when needed 77 // rather than use this flag. 78 args.push_back("-Xnorelocate"); 79 80 ScratchFile profile_file; 81 if (CompilerFilter::DependsOnProfile(filter)) { 82 args.push_back("--profile-file=" + profile_file.GetFilename()); 83 } 84 85 if (pic) { 86 args.push_back("--compile-pic"); 87 } 88 89 std::string image_location = GetImageLocation(); 90 if (with_alternate_image) { 91 args.push_back("--boot-image=" + GetImageLocation2()); 92 } 93 94 if (compilation_reason != nullptr) { 95 args.push_back("--compilation-reason=" + std::string(compilation_reason)); 96 } 97 98 std::string error_msg; 99 ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; 100 101 if (!relocate) { 102 // Restore the dalvik cache if needed. 103 ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno); 104 oat_location = oat_location_in; 105 } 106 107 // Verify the odex file was generated as expected. 108 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 109 oat_location.c_str(), 110 oat_location.c_str(), 111 nullptr, 112 nullptr, 113 false, 114 /*low_4gb*/false, 115 dex_location.c_str(), 116 &error_msg)); 117 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; 118 EXPECT_EQ(pic, odex_file->IsPic()); 119 EXPECT_EQ(filter, odex_file->GetCompilerFilter()); 120 121 std::unique_ptr<ImageHeader> image_header( 122 gc::space::ImageSpace::ReadImageHeader(image_location.c_str(), 123 kRuntimeISA, 124 &error_msg)); 125 ASSERT_TRUE(image_header != nullptr) << error_msg; 126 const OatHeader& oat_header = odex_file->GetOatHeader(); 127 uint32_t combined_checksum = image_header->GetOatChecksum(); 128 129 if (CompilerFilter::DependsOnImageChecksum(filter)) { 130 if (with_alternate_image) { 131 EXPECT_NE(combined_checksum, oat_header.GetImageFileLocationOatChecksum()); 132 } else { 133 EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum()); 134 } 135 } 136 137 if (!with_alternate_image) { 138 if (CompilerFilter::IsAotCompilationEnabled(filter)) { 139 if (relocate) { 140 EXPECT_EQ(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()), 141 oat_header.GetImageFileLocationOatDataBegin()); 142 EXPECT_EQ(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta()); 143 } else { 144 EXPECT_NE(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()), 145 oat_header.GetImageFileLocationOatDataBegin()); 146 EXPECT_NE(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta()); 147 } 148 } 149 } 150 } 151 152 void DexoptTest::GenerateOdexForTest(const std::string& dex_location, 153 const std::string& odex_location, 154 CompilerFilter::Filter filter) { 155 GenerateOatForTest(dex_location, 156 odex_location, 157 filter, 158 /*relocate*/false, 159 /*pic*/false, 160 /*with_alternate_image*/false); 161 } 162 163 void DexoptTest::GeneratePicOdexForTest(const std::string& dex_location, 164 const std::string& odex_location, 165 CompilerFilter::Filter filter, 166 const char* compilation_reason) { 167 GenerateOatForTest(dex_location, 168 odex_location, 169 filter, 170 /*relocate*/false, 171 /*pic*/true, 172 /*with_alternate_image*/false, 173 compilation_reason); 174 } 175 176 void DexoptTest::GenerateOatForTest(const char* dex_location, 177 CompilerFilter::Filter filter, 178 bool relocate, 179 bool pic, 180 bool with_alternate_image) { 181 std::string oat_location; 182 std::string error_msg; 183 ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename( 184 dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg; 185 GenerateOatForTest(dex_location, 186 oat_location, 187 filter, 188 relocate, 189 pic, 190 with_alternate_image); 191 } 192 193 void DexoptTest::GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) { 194 GenerateOatForTest(dex_location, 195 filter, 196 /*relocate*/true, 197 /*pic*/false, 198 /*with_alternate_image*/false); 199 } 200 201 bool DexoptTest::PreRelocateImage(const std::string& image_location, std::string* error_msg) { 202 std::string dalvik_cache; 203 bool have_android_data; 204 bool dalvik_cache_exists; 205 bool is_global_cache; 206 GetDalvikCache(GetInstructionSetString(kRuntimeISA), 207 true, 208 &dalvik_cache, 209 &have_android_data, 210 &dalvik_cache_exists, 211 &is_global_cache); 212 if (!dalvik_cache_exists) { 213 *error_msg = "Failed to create dalvik cache"; 214 return false; 215 } 216 217 std::string patchoat = GetAndroidRoot(); 218 patchoat += kIsDebugBuild ? "/bin/patchoatd" : "/bin/patchoat"; 219 220 std::vector<std::string> argv; 221 argv.push_back(patchoat); 222 argv.push_back("--input-image-location=" + image_location); 223 argv.push_back("--output-image-directory=" + dalvik_cache); 224 argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA))); 225 argv.push_back("--base-offset-delta=0x00008000"); 226 return Exec(argv, error_msg); 227 } 228 229 void DexoptTest::ReserveImageSpace() { 230 MemMap::Init(); 231 232 // Ensure a chunk of memory is reserved for the image space. 233 // The reservation_end includes room for the main space that has to come 234 // right after the image in case of the GSS collector. 235 uint64_t reservation_start = ART_BASE_ADDRESS; 236 uint64_t reservation_end = ART_BASE_ADDRESS + 384 * MB; 237 238 std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true)); 239 ASSERT_TRUE(map.get() != nullptr) << "Failed to build process map"; 240 for (BacktraceMap::iterator it = map->begin(); 241 reservation_start < reservation_end && it != map->end(); ++it) { 242 const backtrace_map_t* entry = *it; 243 ReserveImageSpaceChunk(reservation_start, std::min(entry->start, reservation_end)); 244 reservation_start = std::max(reservation_start, entry->end); 245 } 246 ReserveImageSpaceChunk(reservation_start, reservation_end); 247 } 248 249 void DexoptTest::ReserveImageSpaceChunk(uintptr_t start, uintptr_t end) { 250 if (start < end) { 251 std::string error_msg; 252 image_reservation_.push_back(std::unique_ptr<MemMap>( 253 MemMap::MapAnonymous("image reservation", 254 reinterpret_cast<uint8_t*>(start), end - start, 255 PROT_NONE, false, false, &error_msg))); 256 ASSERT_TRUE(image_reservation_.back().get() != nullptr) << error_msg; 257 LOG(INFO) << "Reserved space for image " << 258 reinterpret_cast<void*>(image_reservation_.back()->Begin()) << "-" << 259 reinterpret_cast<void*>(image_reservation_.back()->End()); 260 } 261 } 262 263 void DexoptTest::UnreserveImageSpace() { 264 image_reservation_.clear(); 265 } 266 267 } // namespace art 268