1 /* 2 * Copyright (C) 2014 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 #ifndef ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ 18 #define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ 19 20 #include <fstream> 21 #include <optional> 22 #include <string> 23 #include <vector> 24 25 #include "base/file_utils.h" 26 #include "base/macros.h" 27 #include "base/os.h" 28 #include "base/stl_util.h" 29 #include "base/utils.h" 30 #include "common_runtime_test.h" 31 #include "compiler_callbacks.h" 32 #include "dex/art_dex_file_loader.h" 33 #include "dex/dex_file_loader.h" 34 #include "exec_utils.h" 35 #include "gc/heap.h" 36 #include "gc/space/image_space.h" 37 #include "gtest/gtest.h" 38 #include "oat/oat_file_assistant.h" 39 #include "runtime.h" 40 #include "ziparchive/zip_writer.h" 41 42 namespace art HIDDEN { 43 44 static constexpr bool kDebugArgs = false; 45 46 class Dex2oatScratchDirs { 47 public: SetUp(const std::string & android_data)48 void SetUp(const std::string& android_data) { 49 // Create a scratch directory to work from. 50 51 // Get the realpath of the android data. The oat dir should always point to real location 52 // when generating oat files in dalvik-cache. This avoids complicating the unit tests 53 // when matching the expected paths. 54 UniqueCPtr<const char[]> android_data_real(realpath(android_data.c_str(), nullptr)); 55 ASSERT_TRUE(android_data_real != nullptr) 56 << "Could not get the realpath of the android data" << android_data << strerror(errno); 57 58 scratch_dir_.assign(android_data_real.get()); 59 scratch_dir_ += "/Dex2oatEnvironmentTest"; 60 ASSERT_EQ(0, mkdir(scratch_dir_.c_str(), 0700)); 61 62 // Create a subdirectory in scratch for odex files. 63 odex_oat_dir_ = scratch_dir_ + "/oat"; 64 ASSERT_EQ(0, mkdir(odex_oat_dir_.c_str(), 0700)); 65 66 odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA)); 67 ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700)); 68 } 69 TearDown()70 void TearDown() { 71 CommonArtTest::ClearDirectory(odex_dir_.c_str()); 72 ASSERT_EQ(0, rmdir(odex_dir_.c_str())); 73 74 CommonArtTest::ClearDirectory(odex_oat_dir_.c_str()); 75 ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str())); 76 77 CommonArtTest::ClearDirectory(scratch_dir_.c_str()); 78 ASSERT_EQ(0, rmdir(scratch_dir_.c_str())); 79 } 80 81 // Scratch directory, for dex and odex files (oat files will go in the 82 // dalvik cache). GetScratchDir()83 const std::string& GetScratchDir() const { return scratch_dir_; } 84 85 // Odex directory is the subdirectory in the scratch directory where odex 86 // files should be located. GetOdexDir()87 const std::string& GetOdexDir() const { return odex_dir_; } 88 89 private: 90 std::string scratch_dir_; 91 std::string odex_oat_dir_; 92 std::string odex_dir_; 93 }; 94 95 // Test class that provides some helpers to set a test up for compilation using dex2oat. 96 class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTest { 97 public: SetUp()98 void SetUp() override { 99 CommonRuntimeTest::SetUp(); 100 Dex2oatScratchDirs::SetUp(android_data_); 101 102 // Verify the environment is as we expect 103 std::optional<uint32_t> checksum; 104 std::string error_msg; 105 ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str())) 106 << "Expected pre-compiled boot image to be at: " << GetSystemImageFile(); 107 ASSERT_TRUE(OS::FileExists(GetDexSrc1().c_str())) 108 << "Expected dex file to be at: " << GetDexSrc1(); 109 ASSERT_TRUE(OS::FileExists(GetResourceOnlySrc1().c_str())) 110 << "Expected stripped dex file to be at: " << GetResourceOnlySrc1(); 111 ArtDexFileLoader dex_file_loader0(GetResourceOnlySrc1()); 112 ASSERT_TRUE(dex_file_loader0.GetMultiDexChecksum(&checksum, &error_msg)) 113 << "Expected stripped dex file to be stripped: " << GetResourceOnlySrc1(); 114 ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str())) 115 << "Expected dex file to be at: " << GetDexSrc2(); 116 117 // GetMultiDexSrc2 should have the same primary dex checksum as 118 // GetMultiDexSrc1, but a different secondary dex checksum. 119 static constexpr bool kVerifyChecksum = true; 120 std::vector<std::unique_ptr<const DexFile>> multi1; 121 ArtDexFileLoader dex_file_loader1(GetMultiDexSrc1()); 122 ASSERT_TRUE(dex_file_loader1.Open(/* verify= */ true, kVerifyChecksum, &error_msg, &multi1)) 123 << error_msg; 124 ASSERT_GT(multi1.size(), 1u); 125 126 std::vector<std::unique_ptr<const DexFile>> multi2; 127 ArtDexFileLoader dex_file_loader2(GetMultiDexSrc2()); 128 ASSERT_TRUE(dex_file_loader2.Open(/* verify= */ true, kVerifyChecksum, &error_msg, &multi2)) 129 << error_msg; 130 ASSERT_GT(multi2.size(), 1u); 131 132 ASSERT_EQ(multi1[0]->GetHeader().checksum_, multi2[0]->GetHeader().checksum_); 133 ASSERT_NE(multi1[1]->GetHeader().checksum_, multi2[1]->GetHeader().checksum_); 134 135 if (multi1[0]->HasDexContainer()) { 136 // Checksum is the CRC of the whole container, so both of them should differ. 137 ASSERT_NE(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum()); 138 ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum()); 139 } else { 140 ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum()); 141 ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum()); 142 } 143 } 144 SetUpRuntimeOptions(RuntimeOptions * options)145 void SetUpRuntimeOptions(RuntimeOptions* options) override { 146 // options->push_back(std::make_pair("-verbose:oat", nullptr)); 147 148 // Set up the image location. 149 options->push_back(std::make_pair("-Ximage:" + GetImageLocation(), 150 nullptr)); 151 // Make sure compilercallbacks are not set so that relocation will be 152 // enabled. 153 callbacks_.reset(); 154 } 155 TearDown()156 void TearDown() override { 157 Dex2oatScratchDirs::TearDown(); 158 CommonRuntimeTest::TearDown(); 159 } 160 Copy(const std::string & src,const std::string & dst)161 static void Copy(const std::string& src, const std::string& dst) { 162 std::ifstream src_stream(src, std::ios::binary); 163 std::ofstream dst_stream(dst, std::ios::binary); 164 165 dst_stream << src_stream.rdbuf(); 166 } 167 GetDexSrc1()168 std::string GetDexSrc1() const { 169 return GetTestDexFileName("Main"); 170 } 171 172 // Returns the path to a dex file equivalent to GetDexSrc1, but with the dex 173 // file stripped. GetResourceOnlySrc1()174 std::string GetResourceOnlySrc1() const { 175 return GetTestDexFileName("MainStripped"); 176 } 177 GetMultiDexSrc1()178 std::string GetMultiDexSrc1() const { 179 return GetTestDexFileName("MultiDex"); 180 } 181 GetMultiDexUncompressedAlignedSrc1()182 std::string GetMultiDexUncompressedAlignedSrc1() const { 183 return GetTestDexFileName("MultiDexUncompressedAligned"); 184 } 185 186 // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but 187 // with the contents of the secondary dex file changed. GetMultiDexSrc2()188 std::string GetMultiDexSrc2() const { 189 return GetTestDexFileName("MultiDexModifiedSecondary"); 190 } 191 GetDexSrc2()192 std::string GetDexSrc2() const { 193 return GetTestDexFileName("Nested"); 194 } 195 Dex2Oat(const std::vector<std::string> & dex2oat_args,std::string * output,std::string * error_msg)196 int Dex2Oat(const std::vector<std::string>& dex2oat_args, 197 std::string* output, 198 std::string* error_msg) { 199 std::vector<std::string> argv; 200 if (!CommonRuntimeTest::StartDex2OatCommandLine(&argv, error_msg)) { 201 ::testing::AssertionFailure() << "Could not start dex2oat cmd line " << *error_msg; 202 } 203 204 Runtime* runtime = Runtime::Current(); 205 if (!runtime->IsVerificationEnabled()) { 206 argv.push_back("--compiler-filter=assume-verified"); 207 } 208 209 if (runtime->MustRelocateIfPossible()) { 210 argv.push_back("--runtime-arg"); 211 argv.push_back("-Xrelocate"); 212 } else { 213 argv.push_back("--runtime-arg"); 214 argv.push_back("-Xnorelocate"); 215 } 216 217 if (!kIsTargetBuild) { 218 argv.push_back("--host"); 219 } 220 221 argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end()); 222 223 // We must set --android-root. 224 const char* android_root = getenv("ANDROID_ROOT"); 225 CHECK(android_root != nullptr); 226 argv.push_back("--android-root=" + std::string(android_root)); 227 228 if (kDebugArgs) { 229 std::string all_args; 230 for (const std::string& arg : argv) { 231 all_args += arg + " "; 232 } 233 LOG(ERROR) << all_args; 234 } 235 236 // We need dex2oat to actually log things. 237 auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:d", 1) == 0; }; 238 ForkAndExecResult res = ForkAndExec(argv, post_fork_fn, output); 239 if (res.stage != ForkAndExecResult::kFinished) { 240 *error_msg = strerror(errno); 241 ::testing::AssertionFailure() << "Failed to finish dex2oat invocation: " << *error_msg; 242 } 243 244 if (!res.StandardSuccess()) { 245 // We cannot use ASSERT_TRUE since the method returns an int and not void. 246 ::testing::AssertionFailure() << "dex2oat fork/exec failed: " << *error_msg; 247 } 248 249 return res.status_code; 250 } 251 CreateDexMetadata(const std::string & vdex,const std::string & out_dm)252 void CreateDexMetadata(const std::string& vdex, const std::string& out_dm) { 253 // Read the vdex bytes. 254 std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex.c_str())); 255 std::vector<uint8_t> data(vdex_file->GetLength()); 256 ASSERT_TRUE(vdex_file->ReadFully(data.data(), data.size())); 257 258 // Zip the content. 259 FILE* file = fopen(out_dm.c_str(), "wbe"); 260 ZipWriter writer(file); 261 writer.StartEntry("primary.vdex", ZipWriter::kAlign32); 262 writer.WriteBytes(data.data(), data.size()); 263 writer.FinishEntry(); 264 writer.Finish(); 265 fflush(file); 266 fclose(file); 267 } 268 }; 269 270 } // namespace art 271 272 #endif // ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ 273