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