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