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 #include <string> 18 #include <vector> 19 #include <sys/param.h> 20 21 #include "android-base/strings.h" 22 #include <gtest/gtest.h> 23 24 #include "art_field-inl.h" 25 #include "class_linker-inl.h" 26 #include "dexopt_test.h" 27 #include "oat_file_assistant.h" 28 #include "oat_file_manager.h" 29 #include "os.h" 30 #include "scoped_thread_state_change-inl.h" 31 #include "thread-inl.h" 32 #include "utils.h" 33 34 namespace art { 35 36 class OatFileAssistantTest : public DexoptTest {}; 37 38 class OatFileAssistantNoDex2OatTest : public DexoptTest { 39 public: 40 virtual void SetUpRuntimeOptions(RuntimeOptions* options) { 41 DexoptTest::SetUpRuntimeOptions(options); 42 options->push_back(std::make_pair("-Xnodex2oat", nullptr)); 43 } 44 }; 45 46 class ScopedNonWritable { 47 public: 48 explicit ScopedNonWritable(const std::string& dex_location) { 49 is_valid_ = false; 50 size_t pos = dex_location.rfind('/'); 51 if (pos != std::string::npos) { 52 is_valid_ = true; 53 dex_parent_ = dex_location.substr(0, pos); 54 if (chmod(dex_parent_.c_str(), 0555) != 0) { 55 PLOG(ERROR) << "Could not change permissions on " << dex_parent_; 56 } 57 } 58 } 59 60 bool IsSuccessful() { return is_valid_ && (access(dex_parent_.c_str(), W_OK) != 0); } 61 62 ~ScopedNonWritable() { 63 if (is_valid_) { 64 if (chmod(dex_parent_.c_str(), 0777) != 0) { 65 PLOG(ERROR) << "Could not restore permissions on " << dex_parent_; 66 } 67 } 68 } 69 70 private: 71 std::string dex_parent_; 72 bool is_valid_; 73 }; 74 75 static bool IsExecutedAsRoot() { 76 return geteuid() == 0; 77 } 78 79 // Case: We have a DEX file, but no OAT file for it. 80 // Expect: The status is kDex2OatNeeded. 81 TEST_F(OatFileAssistantTest, DexNoOat) { 82 std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; 83 Copy(GetDexSrc1(), dex_location); 84 85 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 86 87 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 88 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 89 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 90 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 91 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 92 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile)); 93 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 94 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 95 96 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 97 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 98 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 99 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 100 } 101 102 // Case: We have no DEX file and no OAT file. 103 // Expect: Status is kNoDexOptNeeded. Loading should fail, but not crash. 104 TEST_F(OatFileAssistantTest, NoDexNoOat) { 105 std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar"; 106 107 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 108 109 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 110 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 111 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); 112 113 // Trying to make the oat file up to date should not fail or crash. 114 std::string error_msg; 115 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, oat_file_assistant.MakeUpToDate(false, &error_msg)); 116 117 // Trying to get the best oat file should fail, but not crash. 118 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 119 EXPECT_EQ(nullptr, oat_file.get()); 120 } 121 122 // Case: We have a DEX file and a PIC ODEX file, but no OAT file. 123 // Expect: The status is kNoDexOptNeeded, because PIC needs no relocation. 124 TEST_F(OatFileAssistantTest, OdexUpToDate) { 125 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar"; 126 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex"; 127 Copy(GetDexSrc1(), dex_location); 128 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 129 130 // For the use of oat location by making the dex parent not writable. 131 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 132 133 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 134 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 135 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 136 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 137 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 138 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 139 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, 140 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything)); 141 142 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 143 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); 144 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 145 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 146 } 147 148 // Case: We have a DEX file and a PIC ODEX file, but no OAT file. We load the dex 149 // file via a symlink. 150 // Expect: The status is kNoDexOptNeeded, because PIC needs no relocation. 151 TEST_F(OatFileAssistantTest, OdexUpToDateSymLink) { 152 std::string scratch_dir = GetScratchDir(); 153 std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar"; 154 std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex"; 155 156 Copy(GetDexSrc1(), dex_location); 157 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 158 159 // Now replace the dex location with a symlink. 160 std::string link = scratch_dir + "/link"; 161 ASSERT_EQ(0, symlink(scratch_dir.c_str(), link.c_str())); 162 dex_location = link + "/OdexUpToDate.jar"; 163 164 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 165 166 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 167 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 168 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 169 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 170 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 171 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 172 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, 173 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything)); 174 175 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 176 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); 177 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 178 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 179 } 180 181 // Case: We have a DEX file and up-to-date OAT file for it. 182 // Expect: The status is kNoDexOptNeeded. 183 TEST_F(OatFileAssistantTest, OatUpToDate) { 184 if (IsExecutedAsRoot()) { 185 // We cannot simulate non writable locations when executed as root: b/38000545. 186 LOG(ERROR) << "Test skipped because it's running as root"; 187 return; 188 } 189 190 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar"; 191 Copy(GetDexSrc1(), dex_location); 192 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 193 194 // For the use of oat location by making the dex parent not writable. 195 ScopedNonWritable scoped_non_writable(dex_location); 196 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 197 198 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 199 200 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 201 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 202 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 203 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 204 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 205 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 206 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, 207 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything)); 208 209 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 210 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 211 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus()); 212 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 213 } 214 215 // Case: We have a DEX file and up-to-date OAT file for it. We load the dex file 216 // via a symlink. 217 // Expect: The status is kNoDexOptNeeded. 218 TEST_F(OatFileAssistantTest, OatUpToDateSymLink) { 219 if (IsExecutedAsRoot()) { 220 // We cannot simulate non writable locations when executed as root: b/38000545. 221 LOG(ERROR) << "Test skipped because it's running as root"; 222 return; 223 } 224 225 std::string real = GetScratchDir() + "/real"; 226 ASSERT_EQ(0, mkdir(real.c_str(), 0700)); 227 std::string link = GetScratchDir() + "/link"; 228 ASSERT_EQ(0, symlink(real.c_str(), link.c_str())); 229 230 std::string dex_location = real + "/OatUpToDate.jar"; 231 232 Copy(GetDexSrc1(), dex_location); 233 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 234 235 // Update the dex location to point to the symlink. 236 dex_location = link + "/OatUpToDate.jar"; 237 238 // For the use of oat location by making the dex parent not writable. 239 ScopedNonWritable scoped_non_writable(dex_location); 240 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 241 242 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 243 244 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 245 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 246 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 247 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 248 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 249 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 250 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, 251 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything)); 252 253 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 254 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 255 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus()); 256 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 257 } 258 259 // Case: We have a DEX file and up-to-date (ODEX) VDEX file for it, but no 260 // ODEX file. 261 TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) { 262 // This test case is only meaningful if vdex is enabled. 263 if (!kIsVdexEnabled) { 264 return; 265 } 266 267 std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOdex.jar"; 268 std::string odex_location = GetOdexDir() + "/VdexUpToDateNoOdex.oat"; 269 270 Copy(GetDexSrc1(), dex_location); 271 272 // Generating and deleting the oat file should have the side effect of 273 // creating an up-to-date vdex file. 274 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 275 ASSERT_EQ(0, unlink(odex_location.c_str())); 276 277 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 278 279 // Even though the vdex file is up to date, because we don't have the oat 280 // file, we can't know that the vdex depends on the boot image and is up to 281 // date with respect to the boot image. Instead we must assume the vdex file 282 // depends on the boot image and is out of date with respect to the boot 283 // image. 284 EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage, 285 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 286 287 // Make sure we don't crash in this case when we dump the status. We don't 288 // care what the actual dumped value is. 289 oat_file_assistant.GetStatusDump(); 290 } 291 292 // Case: We have a DEX file and empty VDEX and ODEX files. 293 TEST_F(OatFileAssistantTest, EmptyVdexOdex) { 294 std::string dex_location = GetScratchDir() + "/EmptyVdexOdex.jar"; 295 std::string odex_location = GetOdexDir() + "/EmptyVdexOdex.oat"; 296 std::string vdex_location = GetOdexDir() + "/EmptyVdexOdex.vdex"; 297 298 Copy(GetDexSrc1(), dex_location); 299 ScratchFile vdex_file(vdex_location.c_str()); 300 ScratchFile odex_file(odex_location.c_str()); 301 302 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 303 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 304 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 305 } 306 307 // Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT 308 // file. 309 TEST_F(OatFileAssistantTest, VdexUpToDateNoOat) { 310 // This test case is only meaningful if vdex is enabled. 311 if (!kIsVdexEnabled) { 312 return; 313 } 314 if (IsExecutedAsRoot()) { 315 // We cannot simulate non writable locations when executed as root: b/38000545. 316 LOG(ERROR) << "Test skipped because it's running as root"; 317 return; 318 } 319 320 std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOat.jar"; 321 std::string oat_location; 322 std::string error_msg; 323 ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename( 324 dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg; 325 326 Copy(GetDexSrc1(), dex_location); 327 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 328 ASSERT_EQ(0, unlink(oat_location.c_str())); 329 330 ScopedNonWritable scoped_non_writable(dex_location); 331 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 332 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 333 334 // Even though the vdex file is up to date, because we don't have the oat 335 // file, we can't know that the vdex depends on the boot image and is up to 336 // date with respect to the boot image. Instead we must assume the vdex file 337 // depends on the boot image and is out of date with respect to the boot 338 // image. 339 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage, 340 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 341 } 342 343 // Case: We have a DEX file and speed-profile OAT file for it. 344 // Expect: The status is kNoDexOptNeeded if the profile hasn't changed, but 345 // kDex2Oat if the profile has changed. 346 TEST_F(OatFileAssistantTest, ProfileOatUpToDate) { 347 if (IsExecutedAsRoot()) { 348 // We cannot simulate non writable locations when executed as root: b/38000545. 349 LOG(ERROR) << "Test skipped because it's running as root"; 350 return; 351 } 352 353 std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar"; 354 Copy(GetDexSrc1(), dex_location); 355 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile); 356 357 ScopedNonWritable scoped_non_writable(dex_location); 358 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 359 360 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 361 362 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 363 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, false)); 364 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 365 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken, false)); 366 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, 367 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, true)); 368 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, 369 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken, true)); 370 371 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 372 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 373 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus()); 374 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 375 } 376 377 // Case: We have a MultiDEX file and up-to-date OAT file for it. 378 // Expect: The status is kNoDexOptNeeded and we load all dex files. 379 TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) { 380 if (IsExecutedAsRoot()) { 381 // We cannot simulate non writable locations when executed as root: b/38000545. 382 LOG(ERROR) << "Test skipped because it's running as root"; 383 return; 384 } 385 386 std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar"; 387 Copy(GetMultiDexSrc1(), dex_location); 388 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 389 390 ScopedNonWritable scoped_non_writable(dex_location); 391 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 392 393 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 394 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 395 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false)); 396 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 397 398 // Verify we can load both dex files. 399 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 400 ASSERT_TRUE(oat_file.get() != nullptr); 401 EXPECT_TRUE(oat_file->IsExecutable()); 402 std::vector<std::unique_ptr<const DexFile>> dex_files; 403 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 404 EXPECT_EQ(2u, dex_files.size()); 405 } 406 407 // Case: We have a MultiDEX file where the non-main multdex entry is out of date. 408 // Expect: The status is kDex2OatNeeded. 409 TEST_F(OatFileAssistantTest, MultiDexNonMainOutOfDate) { 410 if (IsExecutedAsRoot()) { 411 // We cannot simulate non writable locations when executed as root: b/38000545. 412 LOG(ERROR) << "Test skipped because it's running as root"; 413 return; 414 } 415 416 std::string dex_location = GetScratchDir() + "/MultiDexNonMainOutOfDate.jar"; 417 418 // Compile code for GetMultiDexSrc1. 419 Copy(GetMultiDexSrc1(), dex_location); 420 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 421 422 // Now overwrite the dex file with GetMultiDexSrc2 so the non-main checksum 423 // is out of date. 424 Copy(GetMultiDexSrc2(), dex_location); 425 426 ScopedNonWritable scoped_non_writable(dex_location); 427 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 428 429 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 430 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 431 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false)); 432 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 433 } 434 435 // Case: We have a stripped MultiDEX file where the non-main multidex entry is 436 // out of date with respect to the odex file. 437 TEST_F(OatFileAssistantTest, StrippedMultiDexNonMainOutOfDate) { 438 std::string dex_location = GetScratchDir() + "/StrippedMultiDexNonMainOutOfDate.jar"; 439 std::string odex_location = GetOdexDir() + "/StrippedMultiDexNonMainOutOfDate.odex"; 440 441 // Compile the oat from GetMultiDexSrc1. 442 Copy(GetMultiDexSrc1(), dex_location); 443 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 444 445 // Compile the odex from GetMultiDexSrc2, which has a different non-main 446 // dex checksum. 447 Copy(GetMultiDexSrc2(), dex_location); 448 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kQuicken); 449 450 // Strip the dex file. 451 Copy(GetStrippedDexSrc1(), dex_location); 452 453 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, /*load_executable*/false); 454 455 // Because the dex file is stripped, the odex file is considered the source 456 // of truth for the dex checksums. The oat file should be considered 457 // unusable. 458 std::unique_ptr<OatFile> best_file = oat_file_assistant.GetBestOatFile(); 459 ASSERT_TRUE(best_file.get() != nullptr); 460 EXPECT_EQ(best_file->GetLocation(), odex_location); 461 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); 462 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); 463 EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus()); 464 } 465 466 // Case: We have a MultiDEX file and up-to-date ODEX file for it with relative 467 // encoded dex locations. 468 // Expect: The oat file status is kNoDexOptNeeded. 469 TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) { 470 std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar"; 471 std::string odex_location = GetOdexDir() + "/RelativeEncodedDexLocation.odex"; 472 473 // Create the dex file 474 Copy(GetMultiDexSrc1(), dex_location); 475 476 // Create the oat file with relative encoded dex location. 477 std::vector<std::string> args; 478 args.push_back("--dex-file=" + dex_location); 479 args.push_back("--dex-location=" + std::string("RelativeEncodedDexLocation.jar")); 480 args.push_back("--oat-file=" + odex_location); 481 args.push_back("--compiler-filter=speed"); 482 483 std::string error_msg; 484 ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; 485 486 // Verify we can load both dex files. 487 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 488 489 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 490 ASSERT_TRUE(oat_file.get() != nullptr); 491 EXPECT_TRUE(oat_file->IsExecutable()); 492 std::vector<std::unique_ptr<const DexFile>> dex_files; 493 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 494 EXPECT_EQ(2u, dex_files.size()); 495 } 496 497 // Case: We have a DEX file and an OAT file out of date with respect to the 498 // dex checksum. 499 TEST_F(OatFileAssistantTest, OatDexOutOfDate) { 500 if (IsExecutedAsRoot()) { 501 // We cannot simulate non writable locations when executed as root: b/38000545. 502 LOG(ERROR) << "Test skipped because it's running as root"; 503 return; 504 } 505 506 std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar"; 507 508 // We create a dex, generate an oat for it, then overwrite the dex with a 509 // different dex to make the oat out of date. 510 Copy(GetDexSrc1(), dex_location); 511 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 512 Copy(GetDexSrc2(), dex_location); 513 514 ScopedNonWritable scoped_non_writable(dex_location); 515 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 516 517 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 518 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 519 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 520 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 521 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 522 523 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 524 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 525 EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus()); 526 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 527 } 528 529 // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect 530 // to the dex checksum, but no ODEX file. 531 TEST_F(OatFileAssistantTest, VdexDexOutOfDate) { 532 // This test case is only meaningful if vdex is enabled. 533 if (!kIsVdexEnabled) { 534 return; 535 } 536 537 std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar"; 538 std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat"; 539 540 Copy(GetDexSrc1(), dex_location); 541 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 542 ASSERT_EQ(0, unlink(odex_location.c_str())); 543 Copy(GetDexSrc2(), dex_location); 544 545 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 546 547 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 548 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 549 } 550 551 // Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry 552 // is out of date and there is no corresponding ODEX file. 553 TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) { 554 // This test case is only meaningful if vdex is enabled. 555 if (!kIsVdexEnabled) { 556 return; 557 } 558 559 std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar"; 560 std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex"; 561 562 Copy(GetMultiDexSrc1(), dex_location); 563 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 564 ASSERT_EQ(0, unlink(odex_location.c_str())); 565 Copy(GetMultiDexSrc2(), dex_location); 566 567 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 568 569 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 570 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 571 } 572 573 // Case: We have a DEX file and an OAT file out of date with respect to the 574 // boot image. 575 TEST_F(OatFileAssistantTest, OatImageOutOfDate) { 576 if (IsExecutedAsRoot()) { 577 // We cannot simulate non writable locations when executed as root: b/38000545. 578 LOG(ERROR) << "Test skipped because it's running as root"; 579 return; 580 } 581 582 std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar"; 583 584 Copy(GetDexSrc1(), dex_location); 585 GenerateOatForTest(dex_location.c_str(), 586 CompilerFilter::kSpeed, 587 /*relocate*/true, 588 /*pic*/false, 589 /*with_alternate_image*/true); 590 591 ScopedNonWritable scoped_non_writable(dex_location); 592 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 593 594 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 595 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage, 596 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 597 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage, 598 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 599 EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage, 600 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 601 602 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 603 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 604 EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus()); 605 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 606 } 607 608 // Case: We have a DEX file and a verify-at-runtime OAT file out of date with 609 // respect to the boot image. 610 // It shouldn't matter that the OAT file is out of date, because it is 611 // verify-at-runtime. 612 TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) { 613 if (IsExecutedAsRoot()) { 614 // We cannot simulate non writable locations when executed as root: b/38000545. 615 LOG(ERROR) << "Test skipped because it's running as root"; 616 return; 617 } 618 619 std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar"; 620 621 Copy(GetDexSrc1(), dex_location); 622 GenerateOatForTest(dex_location.c_str(), 623 CompilerFilter::kExtract, 624 /*relocate*/true, 625 /*pic*/false, 626 /*with_alternate_image*/true); 627 628 ScopedNonWritable scoped_non_writable(dex_location); 629 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 630 631 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 632 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 633 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 634 EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, 635 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 636 637 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 638 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 639 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus()); 640 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 641 } 642 643 // Case: We have a DEX file and an ODEX file, but no OAT file. 644 TEST_F(OatFileAssistantTest, DexOdexNoOat) { 645 std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar"; 646 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; 647 648 // Create the dex and odex files 649 Copy(GetDexSrc1(), dex_location); 650 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 651 652 // Verify the status. 653 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 654 655 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 656 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 657 EXPECT_EQ(-OatFileAssistant::kDex2OatForRelocation, 658 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 659 660 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 661 EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus()); 662 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 663 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 664 665 // We should still be able to get the non-executable odex file to run from. 666 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 667 ASSERT_TRUE(oat_file.get() != nullptr); 668 } 669 670 // Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file. 671 TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) { 672 std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar"; 673 std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex"; 674 675 // Create the dex and odex files 676 Copy(GetDexSrc1(), dex_location); 677 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 678 679 // Strip the dex file 680 Copy(GetStrippedDexSrc1(), dex_location); 681 682 // Verify the status. 683 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 684 685 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 686 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 687 688 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 689 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); 690 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 691 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); 692 693 // Verify we can load the dex files from it. 694 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 695 ASSERT_TRUE(oat_file.get() != nullptr); 696 EXPECT_TRUE(oat_file->IsExecutable()); 697 std::vector<std::unique_ptr<const DexFile>> dex_files; 698 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 699 EXPECT_EQ(1u, dex_files.size()); 700 } 701 702 // Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file. 703 TEST_F(OatFileAssistantTest, StrippedDexOdexOat) { 704 std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar"; 705 std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex"; 706 707 // Create the oat file from a different dex file so it looks out of date. 708 Copy(GetDexSrc2(), dex_location); 709 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 710 711 // Create the odex file 712 Copy(GetDexSrc1(), dex_location); 713 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 714 715 // Strip the dex file. 716 Copy(GetStrippedDexSrc1(), dex_location); 717 718 // Verify the status. 719 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 720 721 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 722 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 723 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 724 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 725 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, // Compiling from the .vdex file 726 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything)); 727 728 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 729 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); 730 EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus()); 731 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); 732 733 // Verify we can load the dex files from it. 734 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 735 ASSERT_TRUE(oat_file.get() != nullptr); 736 EXPECT_TRUE(oat_file->IsExecutable()); 737 std::vector<std::unique_ptr<const DexFile>> dex_files; 738 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 739 EXPECT_EQ(1u, dex_files.size()); 740 } 741 742 // Case: We have a stripped (or resource-only) DEX file, no ODEX file and no 743 // OAT file. Expect: The status is kNoDexOptNeeded. 744 TEST_F(OatFileAssistantTest, ResourceOnlyDex) { 745 std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar"; 746 747 Copy(GetStrippedDexSrc1(), dex_location); 748 749 // Verify the status. 750 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 751 752 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 753 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 754 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 755 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 756 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 757 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 758 759 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 760 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 761 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 762 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); 763 764 // Make the oat file up to date. This should have no effect. 765 std::string error_msg; 766 Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); 767 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, 768 oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg; 769 770 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 771 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 772 773 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 774 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 775 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 776 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); 777 } 778 779 // Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and 780 // OAT files both have patch delta of 0. 781 // Expect: It shouldn't crash. 782 TEST_F(OatFileAssistantTest, OdexOatOverlap) { 783 std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar"; 784 std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex"; 785 786 // Create the dex, the odex and the oat files. 787 Copy(GetDexSrc1(), dex_location); 788 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 789 GenerateOatForTest(dex_location.c_str(), 790 CompilerFilter::kSpeed, 791 /*relocate*/false, 792 /*pic*/false, 793 /*with_alternate_image*/false); 794 795 // Verify things don't go bad. 796 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 797 798 // -kDex2OatForRelocation is expected rather than kDex2OatForRelocation 799 // based on the assumption that the odex location is more up-to-date than the oat 800 // location, even if they both need relocation. 801 EXPECT_EQ(-OatFileAssistant::kDex2OatForRelocation, 802 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 803 804 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 805 EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus()); 806 EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OatFileStatus()); 807 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 808 809 // Things aren't relocated, so it should fall back to interpreted. 810 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 811 ASSERT_TRUE(oat_file.get() != nullptr); 812 813 EXPECT_FALSE(oat_file->IsExecutable()); 814 std::vector<std::unique_ptr<const DexFile>> dex_files; 815 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 816 EXPECT_EQ(1u, dex_files.size()); 817 } 818 819 // Case: We have a DEX file and a VerifyAtRuntime ODEX file, but no OAT file. 820 // Expect: The status is kNoDexOptNeeded, because VerifyAtRuntime contains no code. 821 TEST_F(OatFileAssistantTest, DexVerifyAtRuntimeOdexNoOat) { 822 std::string dex_location = GetScratchDir() + "/DexVerifyAtRuntimeOdexNoOat.jar"; 823 std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex"; 824 825 // Create the dex and odex files 826 Copy(GetDexSrc1(), dex_location); 827 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract); 828 829 // Verify the status. 830 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 831 832 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 833 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract)); 834 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, 835 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 836 837 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 838 EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus()); 839 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 840 EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); 841 } 842 843 // Case: We have a DEX file and up-to-date OAT file for it. 844 // Expect: We should load an executable dex file. 845 TEST_F(OatFileAssistantTest, LoadOatUpToDate) { 846 if (IsExecutedAsRoot()) { 847 // We cannot simulate non writable locations when executed as root: b/38000545. 848 LOG(ERROR) << "Test skipped because it's running as root"; 849 return; 850 } 851 852 std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar"; 853 854 Copy(GetDexSrc1(), dex_location); 855 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 856 857 ScopedNonWritable scoped_non_writable(dex_location); 858 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 859 860 // Load the oat using an oat file assistant. 861 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 862 863 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 864 ASSERT_TRUE(oat_file.get() != nullptr); 865 EXPECT_TRUE(oat_file->IsExecutable()); 866 std::vector<std::unique_ptr<const DexFile>> dex_files; 867 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 868 EXPECT_EQ(1u, dex_files.size()); 869 } 870 871 // Case: We have a DEX file and up-to-date quicken OAT file for it. 872 // Expect: We should still load the oat file as executable. 873 TEST_F(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) { 874 if (IsExecutedAsRoot()) { 875 // We cannot simulate non writable locations when executed as root: b/38000545. 876 LOG(ERROR) << "Test skipped because it's running as root"; 877 return; 878 } 879 880 std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar"; 881 882 Copy(GetDexSrc1(), dex_location); 883 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken); 884 885 ScopedNonWritable scoped_non_writable(dex_location); 886 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 887 888 // Load the oat using an oat file assistant. 889 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 890 891 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 892 ASSERT_TRUE(oat_file.get() != nullptr); 893 EXPECT_TRUE(oat_file->IsExecutable()); 894 std::vector<std::unique_ptr<const DexFile>> dex_files; 895 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 896 EXPECT_EQ(1u, dex_files.size()); 897 } 898 899 // Case: We have a DEX file and up-to-date OAT file for it. 900 // Expect: Loading non-executable should load the oat non-executable. 901 TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) { 902 if (IsExecutedAsRoot()) { 903 // We cannot simulate non writable locations when executed as root: b/38000545. 904 LOG(ERROR) << "Test skipped because it's running as root"; 905 return; 906 } 907 908 std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar"; 909 910 Copy(GetDexSrc1(), dex_location); 911 912 ScopedNonWritable scoped_non_writable(dex_location); 913 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 914 915 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 916 917 // Load the oat using an oat file assistant. 918 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 919 920 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 921 ASSERT_TRUE(oat_file.get() != nullptr); 922 EXPECT_FALSE(oat_file->IsExecutable()); 923 std::vector<std::unique_ptr<const DexFile>> dex_files; 924 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 925 EXPECT_EQ(1u, dex_files.size()); 926 } 927 928 // Case: We don't have a DEX file and can't write the oat file. 929 // Expect: We should fail to generate the oat file without crashing. 930 TEST_F(OatFileAssistantTest, GenNoDex) { 931 if (IsExecutedAsRoot()) { 932 // We cannot simulate non writable locations when executed as root: b/38000545. 933 LOG(ERROR) << "Test skipped because it's running as root"; 934 return; 935 } 936 937 std::string dex_location = GetScratchDir() + "/GenNoDex.jar"; 938 939 ScopedNonWritable scoped_non_writable(dex_location); 940 ASSERT_TRUE(scoped_non_writable.IsSuccessful()); 941 942 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 943 std::string error_msg; 944 Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); 945 // We should get kUpdateSucceeded from MakeUpToDate since there's nothing 946 // that can be done in this situation. 947 ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, 948 oat_file_assistant.MakeUpToDate(false, &error_msg)); 949 950 // Verify it didn't create an oat in the default location (dalvik-cache). 951 OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false); 952 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, ofm.OatFileStatus()); 953 // Verify it didn't create the odex file in the default location (../oat/isa/...odex) 954 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, ofm.OdexFileStatus()); 955 } 956 957 // Turn an absolute path into a path relative to the current working 958 // directory. 959 static std::string MakePathRelative(const std::string& target) { 960 char buf[MAXPATHLEN]; 961 std::string cwd = getcwd(buf, MAXPATHLEN); 962 963 // Split the target and cwd paths into components. 964 std::vector<std::string> target_path; 965 std::vector<std::string> cwd_path; 966 Split(target, '/', &target_path); 967 Split(cwd, '/', &cwd_path); 968 969 // Reverse the path components, so we can use pop_back(). 970 std::reverse(target_path.begin(), target_path.end()); 971 std::reverse(cwd_path.begin(), cwd_path.end()); 972 973 // Drop the common prefix of the paths. Because we reversed the path 974 // components, this becomes the common suffix of target_path and cwd_path. 975 while (!target_path.empty() && !cwd_path.empty() 976 && target_path.back() == cwd_path.back()) { 977 target_path.pop_back(); 978 cwd_path.pop_back(); 979 } 980 981 // For each element of the remaining cwd_path, add '..' to the beginning 982 // of the target path. Because we reversed the path components, we add to 983 // the end of target_path. 984 for (unsigned int i = 0; i < cwd_path.size(); i++) { 985 target_path.push_back(".."); 986 } 987 988 // Reverse again to get the right path order, and join to get the result. 989 std::reverse(target_path.begin(), target_path.end()); 990 return android::base::Join(target_path, '/'); 991 } 992 993 // Case: Non-absolute path to Dex location. 994 // Expect: Not sure, but it shouldn't crash. 995 TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) { 996 std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar"; 997 Copy(GetDexSrc1(), abs_dex_location); 998 999 std::string dex_location = MakePathRelative(abs_dex_location); 1000 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 1001 1002 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 1003 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 1004 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 1005 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 1006 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 1007 } 1008 1009 // Case: Very short, non-existent Dex location. 1010 // Expect: kNoDexOptNeeded. 1011 TEST_F(OatFileAssistantTest, ShortDexLocation) { 1012 std::string dex_location = "/xx"; 1013 1014 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 1015 1016 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 1017 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 1018 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 1019 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 1020 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 1021 EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); 1022 1023 // Trying to make it up to date should have no effect. 1024 std::string error_msg; 1025 Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); 1026 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, 1027 oat_file_assistant.MakeUpToDate(false, &error_msg)); 1028 EXPECT_TRUE(error_msg.empty()); 1029 } 1030 1031 // Case: Non-standard extension for dex file. 1032 // Expect: The status is kDex2OatNeeded. 1033 TEST_F(OatFileAssistantTest, LongDexExtension) { 1034 std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx"; 1035 Copy(GetDexSrc1(), dex_location); 1036 1037 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 1038 1039 EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, 1040 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 1041 1042 EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); 1043 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); 1044 EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus()); 1045 } 1046 1047 // A task to generate a dex location. Used by the RaceToGenerate test. 1048 class RaceGenerateTask : public Task { 1049 public: 1050 explicit RaceGenerateTask(const std::string& dex_location, const std::string& oat_location) 1051 : dex_location_(dex_location), oat_location_(oat_location), loaded_oat_file_(nullptr) 1052 {} 1053 1054 void Run(Thread* self ATTRIBUTE_UNUSED) { 1055 // Load the dex files, and save a pointer to the loaded oat file, so that 1056 // we can verify only one oat file was loaded for the dex location. 1057 std::vector<std::unique_ptr<const DexFile>> dex_files; 1058 std::vector<std::string> error_msgs; 1059 const OatFile* oat_file = nullptr; 1060 dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat( 1061 dex_location_.c_str(), 1062 /*class_loader*/nullptr, 1063 /*dex_elements*/nullptr, 1064 &oat_file, 1065 &error_msgs); 1066 CHECK(!dex_files.empty()) << android::base::Join(error_msgs, '\n'); 1067 CHECK(dex_files[0]->GetOatDexFile() != nullptr) << dex_files[0]->GetLocation(); 1068 loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile(); 1069 CHECK_EQ(loaded_oat_file_, oat_file); 1070 } 1071 1072 const OatFile* GetLoadedOatFile() const { 1073 return loaded_oat_file_; 1074 } 1075 1076 private: 1077 std::string dex_location_; 1078 std::string oat_location_; 1079 const OatFile* loaded_oat_file_; 1080 }; 1081 1082 // Test the case where multiple processes race to generate an oat file. 1083 // This simulates multiple processes using multiple threads. 1084 // 1085 // We want unique Oat files to be loaded even when there is a race to load. 1086 // TODO: The test case no longer tests locking the way it was intended since we now get multiple 1087 // copies of the same Oat files mapped at different locations. 1088 TEST_F(OatFileAssistantTest, RaceToGenerate) { 1089 std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar"; 1090 std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat"; 1091 1092 // We use the lib core dex file, because it's large, and hopefully should 1093 // take a while to generate. 1094 Copy(GetLibCoreDexFileNames()[0], dex_location); 1095 1096 const int kNumThreads = 32; 1097 Thread* self = Thread::Current(); 1098 ThreadPool thread_pool("Oat file assistant test thread pool", kNumThreads); 1099 std::vector<std::unique_ptr<RaceGenerateTask>> tasks; 1100 for (int i = 0; i < kNumThreads; i++) { 1101 std::unique_ptr<RaceGenerateTask> task(new RaceGenerateTask(dex_location, oat_location)); 1102 thread_pool.AddTask(self, task.get()); 1103 tasks.push_back(std::move(task)); 1104 } 1105 thread_pool.StartWorkers(self); 1106 thread_pool.Wait(self, true, false); 1107 1108 // Verify every task got a unique oat file. 1109 std::set<const OatFile*> oat_files; 1110 for (auto& task : tasks) { 1111 const OatFile* oat_file = task->GetLoadedOatFile(); 1112 EXPECT_TRUE(oat_files.find(oat_file) == oat_files.end()); 1113 oat_files.insert(oat_file); 1114 } 1115 } 1116 1117 // Case: We have a DEX file and an ODEX file, no OAT file, and dex2oat is 1118 // disabled. 1119 // Expect: We should load the odex file non-executable. 1120 TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) { 1121 std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar"; 1122 std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex"; 1123 1124 // Create the dex and odex files 1125 Copy(GetDexSrc1(), dex_location); 1126 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 1127 1128 // Load the oat using an executable oat file assistant. 1129 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 1130 1131 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 1132 ASSERT_TRUE(oat_file.get() != nullptr); 1133 EXPECT_FALSE(oat_file->IsExecutable()); 1134 std::vector<std::unique_ptr<const DexFile>> dex_files; 1135 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 1136 EXPECT_EQ(1u, dex_files.size()); 1137 } 1138 1139 // Case: We have a MultiDEX file and an ODEX file, no OAT file, and dex2oat is 1140 // disabled. 1141 // Expect: We should load the odex file non-executable. 1142 TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) { 1143 std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar"; 1144 std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex"; 1145 1146 // Create the dex and odex files 1147 Copy(GetMultiDexSrc1(), dex_location); 1148 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 1149 1150 // Load the oat using an executable oat file assistant. 1151 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); 1152 1153 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 1154 ASSERT_TRUE(oat_file.get() != nullptr); 1155 EXPECT_FALSE(oat_file->IsExecutable()); 1156 std::vector<std::unique_ptr<const DexFile>> dex_files; 1157 dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str()); 1158 EXPECT_EQ(2u, dex_files.size()); 1159 } 1160 1161 TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { 1162 std::string dex_location = GetScratchDir() + "/RuntimeCompilerFilterOptionUsed.jar"; 1163 Copy(GetDexSrc1(), dex_location); 1164 1165 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 1166 1167 std::string error_msg; 1168 Runtime::Current()->AddCompilerOption("--compiler-filter=quicken"); 1169 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, 1170 oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg; 1171 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 1172 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 1173 EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, 1174 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 1175 1176 Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); 1177 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, 1178 oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg; 1179 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 1180 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); 1181 EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, 1182 oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); 1183 1184 Runtime::Current()->AddCompilerOption("--compiler-filter=bogus"); 1185 EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted, 1186 oat_file_assistant.MakeUpToDate(false, &error_msg)); 1187 } 1188 1189 TEST(OatFileAssistantUtilsTest, DexLocationToOdexFilename) { 1190 std::string error_msg; 1191 std::string odex_file; 1192 1193 EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename( 1194 "/foo/bar/baz.jar", kArm, &odex_file, &error_msg)) << error_msg; 1195 EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file); 1196 1197 EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename( 1198 "/foo/bar/baz.funnyext", kArm, &odex_file, &error_msg)) << error_msg; 1199 EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file); 1200 1201 EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename( 1202 "nopath.jar", kArm, &odex_file, &error_msg)); 1203 EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename( 1204 "/foo/bar/baz_noext", kArm, &odex_file, &error_msg)); 1205 } 1206 1207 // Verify the dexopt status values from dalvik.system.DexFile 1208 // match the OatFileAssistant::DexOptStatus values. 1209 TEST_F(OatFileAssistantTest, DexOptStatusValues) { 1210 std::pair<OatFileAssistant::DexOptNeeded, const char*> mapping[] = { 1211 {OatFileAssistant::kNoDexOptNeeded, "NO_DEXOPT_NEEDED"}, 1212 {OatFileAssistant::kDex2OatFromScratch, "DEX2OAT_FROM_SCRATCH"}, 1213 {OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"}, 1214 {OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"}, 1215 {OatFileAssistant::kDex2OatForRelocation, "DEX2OAT_FOR_RELOCATION"}, 1216 }; 1217 1218 ScopedObjectAccess soa(Thread::Current()); 1219 StackHandleScope<1> hs(soa.Self()); 1220 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 1221 Handle<mirror::Class> dexfile( 1222 hs.NewHandle(linker->FindSystemClass(soa.Self(), "Ldalvik/system/DexFile;"))); 1223 ASSERT_FALSE(dexfile == nullptr); 1224 linker->EnsureInitialized(soa.Self(), dexfile, true, true); 1225 1226 for (std::pair<OatFileAssistant::DexOptNeeded, const char*> field : mapping) { 1227 ArtField* art_field = mirror::Class::FindStaticField( 1228 soa.Self(), dexfile.Get(), field.second, "I"); 1229 ASSERT_FALSE(art_field == nullptr); 1230 EXPECT_EQ(art_field->GetTypeAsPrimitiveType(), Primitive::kPrimInt); 1231 EXPECT_EQ(field.first, art_field->GetInt(dexfile.Get())); 1232 } 1233 } 1234 1235 // Verify that when no compiler filter is passed the default one from OatFileAssistant is used. 1236 TEST_F(OatFileAssistantTest, DefaultMakeUpToDateFilter) { 1237 std::string dex_location = GetScratchDir() + "/TestDex.jar"; 1238 Copy(GetDexSrc1(), dex_location); 1239 1240 OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); 1241 1242 const CompilerFilter::Filter default_filter = 1243 OatFileAssistant::kDefaultCompilerFilterForDexLoading; 1244 std::string error_msg; 1245 EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, 1246 oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg; 1247 EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, 1248 oat_file_assistant.GetDexOptNeeded(default_filter)); 1249 std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); 1250 EXPECT_NE(nullptr, oat_file.get()); 1251 EXPECT_EQ(default_filter, oat_file->GetCompilerFilter()); 1252 } 1253 1254 // TODO: More Tests: 1255 // * Test class linker falls back to unquickened dex for DexNoOat 1256 // * Test class linker falls back to unquickened dex for MultiDexNoOat 1257 // * Test using secondary isa 1258 // * Test for status of oat while oat is being generated (how?) 1259 // * Test case where 32 and 64 bit boot class paths differ, 1260 // and we ask IsInBootClassPath for a class in exactly one of the 32 or 1261 // 64 bit boot class paths. 1262 // * Test unexpected scenarios (?): 1263 // - Dex is stripped, don't have odex. 1264 // - Oat file corrupted after status check, before reload unexecutable 1265 // because it's unrelocated and no dex2oat 1266 } // namespace art 1267