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