Home | History | Annotate | Download | only in dex2oat
      1 /*
      2  * Copyright (C) 2016 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 <regex>
     18 #include <sstream>
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <sys/wait.h>
     23 #include <unistd.h>
     24 
     25 #include "android-base/stringprintf.h"
     26 
     27 #include "common_runtime_test.h"
     28 
     29 #include "base/logging.h"
     30 #include "base/macros.h"
     31 #include "base/mutex-inl.h"
     32 #include "bytecode_utils.h"
     33 #include "dex_file-inl.h"
     34 #include "dex2oat_environment_test.h"
     35 #include "dex2oat_return_codes.h"
     36 #include "jit/profile_compilation_info.h"
     37 #include "oat.h"
     38 #include "oat_file.h"
     39 #include "utils.h"
     40 
     41 namespace art {
     42 
     43 static constexpr size_t kMaxMethodIds = 65535;
     44 static constexpr bool kDebugArgs = false;
     45 
     46 using android::base::StringPrintf;
     47 
     48 class Dex2oatTest : public Dex2oatEnvironmentTest {
     49  public:
     50   virtual void TearDown() OVERRIDE {
     51     Dex2oatEnvironmentTest::TearDown();
     52 
     53     output_ = "";
     54     error_msg_ = "";
     55     success_ = false;
     56   }
     57 
     58  protected:
     59   int GenerateOdexForTestWithStatus(const std::vector<std::string>& dex_locations,
     60                                     const std::string& odex_location,
     61                                     CompilerFilter::Filter filter,
     62                                     std::string* error_msg,
     63                                     const std::vector<std::string>& extra_args = {},
     64                                     bool use_fd = false) {
     65     std::unique_ptr<File> oat_file;
     66     std::vector<std::string> args;
     67     // Add dex file args.
     68     for (const std::string& dex_location : dex_locations) {
     69       args.push_back("--dex-file=" + dex_location);
     70     }
     71     if (use_fd) {
     72       oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
     73       CHECK(oat_file != nullptr) << odex_location;
     74       args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
     75       args.push_back("--oat-location=" + odex_location);
     76     } else {
     77       args.push_back("--oat-file=" + odex_location);
     78     }
     79     args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
     80     args.push_back("--runtime-arg");
     81     args.push_back("-Xnorelocate");
     82 
     83     args.insert(args.end(), extra_args.begin(), extra_args.end());
     84 
     85     int status = Dex2Oat(args, error_msg);
     86     if (oat_file != nullptr) {
     87       CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
     88     }
     89     return status;
     90   }
     91 
     92   void GenerateOdexForTest(const std::string& dex_location,
     93                            const std::string& odex_location,
     94                            CompilerFilter::Filter filter,
     95                            const std::vector<std::string>& extra_args = {},
     96                            bool expect_success = true,
     97                            bool use_fd = false,
     98                            std::function<void(const OatFile&)> check_oat = [](const OatFile&) {}) {
     99     std::string error_msg;
    100     int status = GenerateOdexForTestWithStatus({dex_location},
    101                                                odex_location,
    102                                                filter,
    103                                                &error_msg,
    104                                                extra_args,
    105                                                use_fd);
    106     bool success = (status == 0);
    107     if (expect_success) {
    108       ASSERT_TRUE(success) << error_msg << std::endl << output_;
    109 
    110       // Verify the odex file was generated as expected.
    111       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    112                                                        odex_location.c_str(),
    113                                                        nullptr,
    114                                                        nullptr,
    115                                                        false,
    116                                                        /*low_4gb*/false,
    117                                                        dex_location.c_str(),
    118                                                        &error_msg));
    119       ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    120 
    121       CheckFilter(filter, odex_file->GetCompilerFilter());
    122       check_oat(*(odex_file.get()));
    123     } else {
    124       ASSERT_FALSE(success) << output_;
    125 
    126       error_msg_ = error_msg;
    127 
    128       // Verify there's no loadable odex file.
    129       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    130                                                        odex_location.c_str(),
    131                                                        nullptr,
    132                                                        nullptr,
    133                                                        false,
    134                                                        /*low_4gb*/false,
    135                                                        dex_location.c_str(),
    136                                                        &error_msg));
    137       ASSERT_TRUE(odex_file.get() == nullptr);
    138     }
    139   }
    140 
    141   // Check the input compiler filter against the generated oat file's filter. May be overridden
    142   // in subclasses when equality is not expected.
    143   virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
    144     EXPECT_EQ(expected, actual);
    145   }
    146 
    147   int Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
    148     Runtime* runtime = Runtime::Current();
    149 
    150     const std::vector<gc::space::ImageSpace*>& image_spaces =
    151         runtime->GetHeap()->GetBootImageSpaces();
    152     if (image_spaces.empty()) {
    153       *error_msg = "No image location found for Dex2Oat.";
    154       return false;
    155     }
    156     std::string image_location = image_spaces[0]->GetImageLocation();
    157 
    158     std::vector<std::string> argv;
    159     argv.push_back(runtime->GetCompilerExecutable());
    160 
    161     if (runtime->IsJavaDebuggable()) {
    162       argv.push_back("--debuggable");
    163     }
    164     runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
    165 
    166     if (!runtime->IsVerificationEnabled()) {
    167       argv.push_back("--compiler-filter=assume-verified");
    168     }
    169 
    170     if (runtime->MustRelocateIfPossible()) {
    171       argv.push_back("--runtime-arg");
    172       argv.push_back("-Xrelocate");
    173     } else {
    174       argv.push_back("--runtime-arg");
    175       argv.push_back("-Xnorelocate");
    176     }
    177 
    178     if (!kIsTargetBuild) {
    179       argv.push_back("--host");
    180     }
    181 
    182     argv.push_back("--boot-image=" + image_location);
    183 
    184     std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
    185     argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
    186 
    187     argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
    188 
    189     // We must set --android-root.
    190     const char* android_root = getenv("ANDROID_ROOT");
    191     CHECK(android_root != nullptr);
    192     argv.push_back("--android-root=" + std::string(android_root));
    193 
    194     if (kDebugArgs) {
    195       std::string all_args;
    196       for (const std::string& arg : argv) {
    197         all_args += arg + " ";
    198       }
    199       LOG(ERROR) << all_args;
    200     }
    201 
    202     int link[2];
    203 
    204     if (pipe(link) == -1) {
    205       return false;
    206     }
    207 
    208     pid_t pid = fork();
    209     if (pid == -1) {
    210       return false;
    211     }
    212 
    213     if (pid == 0) {
    214       // We need dex2oat to actually log things.
    215       setenv("ANDROID_LOG_TAGS", "*:d", 1);
    216       dup2(link[1], STDERR_FILENO);
    217       close(link[0]);
    218       close(link[1]);
    219       std::vector<const char*> c_args;
    220       for (const std::string& str : argv) {
    221         c_args.push_back(str.c_str());
    222       }
    223       c_args.push_back(nullptr);
    224       execv(c_args[0], const_cast<char* const*>(c_args.data()));
    225       exit(1);
    226       UNREACHABLE();
    227     } else {
    228       close(link[1]);
    229       char buffer[128];
    230       memset(buffer, 0, 128);
    231       ssize_t bytes_read = 0;
    232 
    233       while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
    234         output_ += std::string(buffer, bytes_read);
    235       }
    236       close(link[0]);
    237       int status = -1;
    238       if (waitpid(pid, &status, 0) != -1) {
    239         success_ = (status == 0);
    240       }
    241       return status;
    242     }
    243   }
    244 
    245   std::string output_ = "";
    246   std::string error_msg_ = "";
    247   bool success_ = false;
    248 };
    249 
    250 class Dex2oatSwapTest : public Dex2oatTest {
    251  protected:
    252   void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
    253     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
    254     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
    255 
    256     Copy(GetTestDexFileName(), dex_location);
    257 
    258     std::vector<std::string> copy(extra_args);
    259 
    260     std::unique_ptr<ScratchFile> sf;
    261     if (use_fd) {
    262       sf.reset(new ScratchFile());
    263       copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
    264     } else {
    265       std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
    266       copy.push_back("--swap-file=" + swap_location);
    267     }
    268     GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
    269 
    270     CheckValidity();
    271     ASSERT_TRUE(success_);
    272     CheckResult(expect_use);
    273   }
    274 
    275   virtual std::string GetTestDexFileName() {
    276     return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps");
    277   }
    278 
    279   virtual void CheckResult(bool expect_use) {
    280     if (kIsTargetBuild) {
    281       CheckTargetResult(expect_use);
    282     } else {
    283       CheckHostResult(expect_use);
    284     }
    285   }
    286 
    287   virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
    288     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
    289     //       something for variants with file descriptor where we can control the lifetime of
    290     //       the swap file and thus take a look at it.
    291   }
    292 
    293   virtual void CheckHostResult(bool expect_use) {
    294     if (!kIsTargetBuild) {
    295       if (expect_use) {
    296         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
    297             << output_;
    298       } else {
    299         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
    300             << output_;
    301       }
    302     }
    303   }
    304 
    305   // Check whether the dex2oat run was really successful.
    306   virtual void CheckValidity() {
    307     if (kIsTargetBuild) {
    308       CheckTargetValidity();
    309     } else {
    310       CheckHostValidity();
    311     }
    312   }
    313 
    314   virtual void CheckTargetValidity() {
    315     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
    316     //       something for variants with file descriptor where we can control the lifetime of
    317     //       the swap file and thus take a look at it.
    318   }
    319 
    320   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
    321   virtual void CheckHostValidity() {
    322     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
    323   }
    324 };
    325 
    326 TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
    327   RunTest(false /* use_fd */, false /* expect_use */);
    328   RunTest(true /* use_fd */, false /* expect_use */);
    329 }
    330 
    331 TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
    332   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
    333   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
    334 }
    335 
    336 TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
    337   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
    338   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
    339 }
    340 
    341 TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
    342   RunTest(false /* use_fd */,
    343           true /* expect_use */,
    344           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
    345   RunTest(true /* use_fd */,
    346           true /* expect_use */,
    347           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
    348 }
    349 
    350 class Dex2oatSwapUseTest : public Dex2oatSwapTest {
    351  protected:
    352   void CheckHostResult(bool expect_use) OVERRIDE {
    353     if (!kIsTargetBuild) {
    354       if (expect_use) {
    355         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
    356             << output_;
    357       } else {
    358         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
    359             << output_;
    360       }
    361     }
    362   }
    363 
    364   std::string GetTestDexFileName() OVERRIDE {
    365     // Use Statics as it has a handful of functions.
    366     return CommonRuntimeTest::GetTestDexFileName("Statics");
    367   }
    368 
    369   void GrabResult1() {
    370     if (!kIsTargetBuild) {
    371       native_alloc_1_ = ParseNativeAlloc();
    372       swap_1_ = ParseSwap(false /* expected */);
    373     } else {
    374       native_alloc_1_ = std::numeric_limits<size_t>::max();
    375       swap_1_ = 0;
    376     }
    377   }
    378 
    379   void GrabResult2() {
    380     if (!kIsTargetBuild) {
    381       native_alloc_2_ = ParseNativeAlloc();
    382       swap_2_ = ParseSwap(true /* expected */);
    383     } else {
    384       native_alloc_2_ = 0;
    385       swap_2_ = std::numeric_limits<size_t>::max();
    386     }
    387   }
    388 
    389  private:
    390   size_t ParseNativeAlloc() {
    391     std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)");
    392     std::smatch native_alloc_match;
    393     bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex);
    394     if (!found) {
    395       EXPECT_TRUE(found);
    396       return 0;
    397     }
    398     if (native_alloc_match.size() != 2U) {
    399       EXPECT_EQ(native_alloc_match.size(), 2U);
    400       return 0;
    401     }
    402 
    403     std::istringstream stream(native_alloc_match[1].str());
    404     size_t value;
    405     stream >> value;
    406 
    407     return value;
    408   }
    409 
    410   size_t ParseSwap(bool expected) {
    411     std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)");
    412     std::smatch swap_match;
    413     bool found = std::regex_search(output_, swap_match, swap_regex);
    414     if (found != expected) {
    415       EXPECT_EQ(expected, found);
    416       return 0;
    417     }
    418 
    419     if (!found) {
    420       return 0;
    421     }
    422 
    423     if (swap_match.size() != 2U) {
    424       EXPECT_EQ(swap_match.size(), 2U);
    425       return 0;
    426     }
    427 
    428     std::istringstream stream(swap_match[1].str());
    429     size_t value;
    430     stream >> value;
    431 
    432     return value;
    433   }
    434 
    435  protected:
    436   size_t native_alloc_1_;
    437   size_t native_alloc_2_;
    438 
    439   size_t swap_1_;
    440   size_t swap_2_;
    441 };
    442 
    443 TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
    444   // Native memory usage isn't correctly tracked under sanitization.
    445   TEST_DISABLED_FOR_MEMORY_TOOL_ASAN();
    446 
    447   // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
    448   // hold true on some x86 systems; disable this test while we
    449   // investigate (b/29259363).
    450   TEST_DISABLED_FOR_X86();
    451 
    452   RunTest(false /* use_fd */,
    453           false /* expect_use */);
    454   GrabResult1();
    455   std::string output_1 = output_;
    456 
    457   output_ = "";
    458 
    459   RunTest(false /* use_fd */,
    460           true /* expect_use */,
    461           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
    462   GrabResult2();
    463   std::string output_2 = output_;
    464 
    465   if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) {
    466     EXPECT_LT(native_alloc_2_, native_alloc_1_);
    467     EXPECT_LT(swap_1_, swap_2_);
    468 
    469     LOG(ERROR) << output_1;
    470     LOG(ERROR) << output_2;
    471   }
    472 }
    473 
    474 class Dex2oatVeryLargeTest : public Dex2oatTest {
    475  protected:
    476   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
    477                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
    478     // Ignore, we'll do our own checks.
    479   }
    480 
    481   void RunTest(CompilerFilter::Filter filter,
    482                bool expect_large,
    483                bool expect_downgrade,
    484                const std::vector<std::string>& extra_args = {}) {
    485     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
    486     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
    487     std::string app_image_file = GetScratchDir() + "/Test.art";
    488 
    489     Copy(GetDexSrc1(), dex_location);
    490 
    491     std::vector<std::string> new_args(extra_args);
    492     new_args.push_back("--app-image-file=" + app_image_file);
    493     GenerateOdexForTest(dex_location, odex_location, filter, new_args);
    494 
    495     CheckValidity();
    496     ASSERT_TRUE(success_);
    497     CheckResult(dex_location,
    498                 odex_location,
    499                 app_image_file,
    500                 filter,
    501                 expect_large,
    502                 expect_downgrade);
    503   }
    504 
    505   void CheckResult(const std::string& dex_location,
    506                    const std::string& odex_location,
    507                    const std::string& app_image_file,
    508                    CompilerFilter::Filter filter,
    509                    bool expect_large,
    510                    bool expect_downgrade) {
    511     if (expect_downgrade) {
    512       EXPECT_TRUE(expect_large);
    513     }
    514     // Host/target independent checks.
    515     std::string error_msg;
    516     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    517                                                      odex_location.c_str(),
    518                                                      nullptr,
    519                                                      nullptr,
    520                                                      false,
    521                                                      /*low_4gb*/false,
    522                                                      dex_location.c_str(),
    523                                                      &error_msg));
    524     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    525     EXPECT_GT(app_image_file.length(), 0u);
    526     std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file.c_str()));
    527     if (expect_large) {
    528       // Note: we cannot check the following
    529       // EXPECT_FALSE(CompilerFilter::IsAotCompilationEnabled(odex_file->GetCompilerFilter()));
    530       // The reason is that the filter override currently happens when the dex files are
    531       // loaded in dex2oat, which is after the oat file has been started. Thus, the header
    532       // store cannot be changed, and the original filter is set in stone.
    533 
    534       for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
    535         std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
    536         ASSERT_TRUE(dex_file != nullptr);
    537         uint32_t class_def_count = dex_file->NumClassDefs();
    538         ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
    539         for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
    540           OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    541           EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
    542         }
    543       }
    544 
    545       // If the input filter was "below," it should have been used.
    546       if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract, filter)) {
    547         EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
    548       }
    549 
    550       // If expect large, make sure the app image isn't generated or is empty.
    551       if (file != nullptr) {
    552         EXPECT_EQ(file->GetLength(), 0u);
    553       }
    554     } else {
    555       EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
    556       ASSERT_TRUE(file != nullptr) << app_image_file;
    557       EXPECT_GT(file->GetLength(), 0u);
    558     }
    559 
    560     // Host/target dependent checks.
    561     if (kIsTargetBuild) {
    562       CheckTargetResult(expect_downgrade);
    563     } else {
    564       CheckHostResult(expect_downgrade);
    565     }
    566   }
    567 
    568   void CheckTargetResult(bool expect_downgrade ATTRIBUTE_UNUSED) {
    569     // TODO: Ignore for now. May do something for fd things.
    570   }
    571 
    572   void CheckHostResult(bool expect_downgrade) {
    573     if (!kIsTargetBuild) {
    574       if (expect_downgrade) {
    575         EXPECT_NE(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
    576       } else {
    577         EXPECT_EQ(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
    578       }
    579     }
    580   }
    581 
    582   // Check whether the dex2oat run was really successful.
    583   void CheckValidity() {
    584     if (kIsTargetBuild) {
    585       CheckTargetValidity();
    586     } else {
    587       CheckHostValidity();
    588     }
    589   }
    590 
    591   void CheckTargetValidity() {
    592     // TODO: Ignore for now.
    593   }
    594 
    595   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
    596   void CheckHostValidity() {
    597     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
    598   }
    599 };
    600 
    601 TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
    602   RunTest(CompilerFilter::kAssumeVerified, false, false);
    603   RunTest(CompilerFilter::kExtract, false, false);
    604   RunTest(CompilerFilter::kQuicken, false, false);
    605   RunTest(CompilerFilter::kSpeed, false, false);
    606 
    607   RunTest(CompilerFilter::kAssumeVerified, false, false, { "--very-large-app-threshold=10000000" });
    608   RunTest(CompilerFilter::kExtract, false, false, { "--very-large-app-threshold=10000000" });
    609   RunTest(CompilerFilter::kQuicken, false, false, { "--very-large-app-threshold=10000000" });
    610   RunTest(CompilerFilter::kSpeed, false, false, { "--very-large-app-threshold=10000000" });
    611 }
    612 
    613 TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
    614   RunTest(CompilerFilter::kAssumeVerified, true, false, { "--very-large-app-threshold=100" });
    615   RunTest(CompilerFilter::kExtract, true, false, { "--very-large-app-threshold=100" });
    616   RunTest(CompilerFilter::kQuicken, true, true, { "--very-large-app-threshold=100" });
    617   RunTest(CompilerFilter::kSpeed, true, true, { "--very-large-app-threshold=100" });
    618 }
    619 
    620 // Regressin test for b/35665292.
    621 TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) {
    622   // Test that dex2oat doesn't crash with speed-profile but no input profile.
    623   RunTest(CompilerFilter::kSpeedProfile, false, false);
    624 }
    625 
    626 class Dex2oatLayoutTest : public Dex2oatTest {
    627  protected:
    628   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
    629                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
    630     // Ignore, we'll do our own checks.
    631   }
    632 
    633   // Emits a profile with a single dex file with the given location and a single class index of 1.
    634   void GenerateProfile(const std::string& test_profile,
    635                        const std::string& dex_location,
    636                        size_t num_classes,
    637                        uint32_t checksum) {
    638     int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
    639     CHECK_GE(profile_test_fd, 0);
    640 
    641     ProfileCompilationInfo info;
    642     std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location);
    643     for (size_t i = 0; i < num_classes; ++i) {
    644       info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i), kMaxMethodIds);
    645     }
    646     bool result = info.Save(profile_test_fd);
    647     close(profile_test_fd);
    648     ASSERT_TRUE(result);
    649   }
    650 
    651   void CompileProfileOdex(const std::string& dex_location,
    652                           const std::string& odex_location,
    653                           const std::string& app_image_file_name,
    654                           bool use_fd,
    655                           size_t num_profile_classes,
    656                           const std::vector<std::string>& extra_args = {},
    657                           bool expect_success = true) {
    658     const std::string profile_location = GetScratchDir() + "/primary.prof";
    659     const char* location = dex_location.c_str();
    660     std::string error_msg;
    661     std::vector<std::unique_ptr<const DexFile>> dex_files;
    662     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
    663     EXPECT_EQ(dex_files.size(), 1U);
    664     std::unique_ptr<const DexFile>& dex_file = dex_files[0];
    665     GenerateProfile(profile_location,
    666                     dex_location,
    667                     num_profile_classes,
    668                     dex_file->GetLocationChecksum());
    669     std::vector<std::string> copy(extra_args);
    670     copy.push_back("--profile-file=" + profile_location);
    671     std::unique_ptr<File> app_image_file;
    672     if (!app_image_file_name.empty()) {
    673       if (use_fd) {
    674         app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str()));
    675         copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd()));
    676       } else {
    677         copy.push_back("--app-image-file=" + app_image_file_name);
    678       }
    679     }
    680     GenerateOdexForTest(dex_location,
    681                         odex_location,
    682                         CompilerFilter::kSpeedProfile,
    683                         copy,
    684                         expect_success,
    685                         use_fd);
    686     if (app_image_file != nullptr) {
    687       ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
    688     }
    689   }
    690 
    691   uint64_t GetImageSize(const std::string& image_file_name) {
    692     EXPECT_FALSE(image_file_name.empty());
    693     std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
    694     CHECK(file != nullptr);
    695     ImageHeader image_header;
    696     const bool success = file->ReadFully(&image_header, sizeof(image_header));
    697     CHECK(success);
    698     CHECK(image_header.IsValid());
    699     ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
    700     return image_header.GetImageSize();
    701   }
    702 
    703   void RunTest(bool app_image) {
    704     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
    705     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
    706     std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): "";
    707     Copy(GetDexSrc2(), dex_location);
    708 
    709     uint64_t image_file_empty_profile = 0;
    710     if (app_image) {
    711       CompileProfileOdex(dex_location,
    712                          odex_location,
    713                          app_image_file,
    714                          /* use_fd */ false,
    715                          /* num_profile_classes */ 0);
    716       CheckValidity();
    717       ASSERT_TRUE(success_);
    718       // Don't check the result since CheckResult relies on the class being in the profile.
    719       image_file_empty_profile = GetImageSize(app_image_file);
    720       EXPECT_GT(image_file_empty_profile, 0u);
    721     }
    722 
    723     // Small profile.
    724     CompileProfileOdex(dex_location,
    725                        odex_location,
    726                        app_image_file,
    727                        /* use_fd */ false,
    728                        /* num_profile_classes */ 1);
    729     CheckValidity();
    730     ASSERT_TRUE(success_);
    731     CheckResult(dex_location, odex_location, app_image_file);
    732 
    733     if (app_image) {
    734       // Test that the profile made a difference by adding more classes.
    735       const uint64_t image_file_small_profile = GetImageSize(app_image_file);
    736       CHECK_LT(image_file_empty_profile, image_file_small_profile);
    737     }
    738   }
    739 
    740   void RunTestVDex() {
    741     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
    742     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
    743     std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
    744     std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art";
    745     Copy(GetDexSrc2(), dex_location);
    746 
    747     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
    748     CHECK(vdex_file1 != nullptr) << vdex_location;
    749     ScratchFile vdex_file2;
    750     {
    751       std::string input_vdex = "--input-vdex-fd=-1";
    752       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
    753       CompileProfileOdex(dex_location,
    754                          odex_location,
    755                          app_image_file_name,
    756                          /* use_fd */ true,
    757                          /* num_profile_classes */ 1,
    758                          { input_vdex, output_vdex });
    759       EXPECT_GT(vdex_file1->GetLength(), 0u);
    760     }
    761     {
    762       // Test that vdex and dexlayout fail gracefully.
    763       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
    764       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
    765       CompileProfileOdex(dex_location,
    766                          odex_location,
    767                          app_image_file_name,
    768                          /* use_fd */ true,
    769                          /* num_profile_classes */ 1,
    770                          { input_vdex, output_vdex },
    771                          /* expect_success */ true);
    772       EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
    773     }
    774     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
    775     CheckValidity();
    776     ASSERT_TRUE(success_);
    777   }
    778 
    779   void CheckResult(const std::string& dex_location,
    780                    const std::string& odex_location,
    781                    const std::string& app_image_file_name) {
    782     // Host/target independent checks.
    783     std::string error_msg;
    784     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    785                                                      odex_location.c_str(),
    786                                                      nullptr,
    787                                                      nullptr,
    788                                                      false,
    789                                                      /*low_4gb*/false,
    790                                                      dex_location.c_str(),
    791                                                      &error_msg));
    792     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    793 
    794     const char* location = dex_location.c_str();
    795     std::vector<std::unique_ptr<const DexFile>> dex_files;
    796     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
    797     EXPECT_EQ(dex_files.size(), 1U);
    798     std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
    799 
    800     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
    801       std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
    802       ASSERT_TRUE(new_dex_file != nullptr);
    803       uint32_t class_def_count = new_dex_file->NumClassDefs();
    804       ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
    805       ASSERT_GE(class_def_count, 2U);
    806 
    807       // The new layout swaps the classes at indexes 0 and 1.
    808       std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
    809       std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
    810       std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
    811       std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
    812       EXPECT_EQ(old_class0, new_class1);
    813       EXPECT_EQ(old_class1, new_class0);
    814     }
    815 
    816     EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
    817 
    818     if (!app_image_file_name.empty()) {
    819       // Go peek at the image header to make sure it was large enough to contain the class.
    820       std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str()));
    821       ImageHeader image_header;
    822       bool success = file->ReadFully(&image_header, sizeof(image_header));
    823       ASSERT_TRUE(success);
    824       ASSERT_TRUE(image_header.IsValid());
    825       EXPECT_GT(image_header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u);
    826     }
    827   }
    828 
    829   // Check whether the dex2oat run was really successful.
    830   void CheckValidity() {
    831     if (kIsTargetBuild) {
    832       CheckTargetValidity();
    833     } else {
    834       CheckHostValidity();
    835     }
    836   }
    837 
    838   void CheckTargetValidity() {
    839     // TODO: Ignore for now.
    840   }
    841 
    842   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
    843   void CheckHostValidity() {
    844     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
    845   }
    846 };
    847 
    848 TEST_F(Dex2oatLayoutTest, TestLayout) {
    849   RunTest(/* app-image */ false);
    850 }
    851 
    852 TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) {
    853   RunTest(/* app-image */ true);
    854 }
    855 
    856 TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
    857   RunTestVDex();
    858 }
    859 
    860 class Dex2oatUnquickenTest : public Dex2oatTest {
    861  protected:
    862   void RunUnquickenMultiDex() {
    863     std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar";
    864     std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex";
    865     std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex";
    866     Copy(GetTestDexFileName("MultiDex"), dex_location);
    867 
    868     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
    869     CHECK(vdex_file1 != nullptr) << vdex_location;
    870     // Quicken the dex file into a vdex file.
    871     {
    872       std::string input_vdex = "--input-vdex-fd=-1";
    873       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
    874       GenerateOdexForTest(dex_location,
    875                           odex_location,
    876                           CompilerFilter::kQuicken,
    877                           { input_vdex, output_vdex },
    878                           /* expect_success */ true,
    879                           /* use_fd */ true);
    880       EXPECT_GT(vdex_file1->GetLength(), 0u);
    881     }
    882     // Unquicken by running the verify compiler filter on the vdex file.
    883     {
    884       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
    885       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
    886       GenerateOdexForTest(dex_location,
    887                           odex_location,
    888                           CompilerFilter::kVerify,
    889                           { input_vdex, output_vdex },
    890                           /* expect_success */ true,
    891                           /* use_fd */ true);
    892     }
    893     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
    894     CheckResult(dex_location, odex_location);
    895     ASSERT_TRUE(success_);
    896   }
    897 
    898   void CheckResult(const std::string& dex_location, const std::string& odex_location) {
    899     std::string error_msg;
    900     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    901                                                      odex_location.c_str(),
    902                                                      nullptr,
    903                                                      nullptr,
    904                                                      false,
    905                                                      /*low_4gb*/false,
    906                                                      dex_location.c_str(),
    907                                                      &error_msg));
    908     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    909     ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u);
    910 
    911     // Iterate over the dex files and ensure there is no quickened instruction.
    912     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
    913       std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
    914       for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
    915         const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
    916         const uint8_t* class_data = dex_file->GetClassData(class_def);
    917         if (class_data != nullptr) {
    918           for (ClassDataItemIterator class_it(*dex_file, class_data);
    919                class_it.HasNext();
    920                class_it.Next()) {
    921             if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
    922               for (CodeItemIterator it(*class_it.GetMethodCodeItem()); !it.Done(); it.Advance()) {
    923                 Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
    924                 ASSERT_FALSE(inst->IsQuickened());
    925               }
    926             }
    927           }
    928         }
    929       }
    930     }
    931   }
    932 };
    933 
    934 TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) {
    935   RunUnquickenMultiDex();
    936 }
    937 
    938 class Dex2oatWatchdogTest : public Dex2oatTest {
    939  protected:
    940   void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {
    941     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
    942     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
    943 
    944     Copy(GetTestDexFileName(), dex_location);
    945 
    946     std::vector<std::string> copy(extra_args);
    947 
    948     std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
    949     copy.push_back("--swap-file=" + swap_location);
    950     GenerateOdexForTest(dex_location,
    951                         odex_location,
    952                         CompilerFilter::kSpeed,
    953                         copy,
    954                         expect_success);
    955   }
    956 
    957   std::string GetTestDexFileName() {
    958     return GetDexSrc1();
    959   }
    960 };
    961 
    962 TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
    963   // Check with default.
    964   RunTest(true);
    965 
    966   // Check with ten minutes.
    967   RunTest(true, { "--watchdog-timeout=600000" });
    968 }
    969 
    970 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
    971   // Check with ten milliseconds.
    972   RunTest(false, { "--watchdog-timeout=10" });
    973 }
    974 
    975 class Dex2oatReturnCodeTest : public Dex2oatTest {
    976  protected:
    977   int RunTest(const std::vector<std::string>& extra_args = {}) {
    978     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
    979     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
    980 
    981     Copy(GetTestDexFileName(), dex_location);
    982 
    983     std::string error_msg;
    984     return GenerateOdexForTestWithStatus({dex_location},
    985                                          odex_location,
    986                                          CompilerFilter::kSpeed,
    987                                          &error_msg,
    988                                          extra_args);
    989   }
    990 
    991   std::string GetTestDexFileName() {
    992     return GetDexSrc1();
    993   }
    994 };
    995 
    996 TEST_F(Dex2oatReturnCodeTest, TestCreateRuntime) {
    997   TEST_DISABLED_FOR_MEMORY_TOOL();  // b/19100793
    998   int status = RunTest({ "--boot-image=/this/does/not/exist/yolo.oat" });
    999   EXPECT_EQ(static_cast<int>(dex2oat::ReturnCode::kCreateRuntime), WEXITSTATUS(status)) << output_;
   1000 }
   1001 
   1002 class Dex2oatClassLoaderContextTest : public Dex2oatTest {
   1003  protected:
   1004   void RunTest(const char* class_loader_context,
   1005                const char* expected_classpath_key,
   1006                bool expected_success,
   1007                bool use_second_source = false) {
   1008     std::string dex_location = GetUsedDexLocation();
   1009     std::string odex_location = GetUsedOatLocation();
   1010 
   1011     Copy(use_second_source ? GetDexSrc2() : GetDexSrc1(), dex_location);
   1012 
   1013     std::string error_msg;
   1014     std::vector<std::string> extra_args;
   1015     if (class_loader_context != nullptr) {
   1016       extra_args.push_back(std::string("--class-loader-context=") + class_loader_context);
   1017     }
   1018     auto check_oat = [expected_classpath_key](const OatFile& oat_file) {
   1019       ASSERT_TRUE(expected_classpath_key != nullptr);
   1020       const char* classpath = oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey);
   1021       ASSERT_TRUE(classpath != nullptr);
   1022       ASSERT_STREQ(expected_classpath_key, classpath);
   1023     };
   1024 
   1025     GenerateOdexForTest(dex_location,
   1026                         odex_location,
   1027                         CompilerFilter::kQuicken,
   1028                         extra_args,
   1029                         expected_success,
   1030                         /*use_fd*/ false,
   1031                         check_oat);
   1032   }
   1033 
   1034   std::string GetUsedDexLocation() {
   1035     return GetScratchDir() + "/Context.jar";
   1036   }
   1037 
   1038   std::string GetUsedOatLocation() {
   1039     return GetOdexDir() + "/Context.odex";
   1040   }
   1041 
   1042   const char* kEmptyClassPathKey = "PCL[]";
   1043 };
   1044 
   1045 TEST_F(Dex2oatClassLoaderContextTest, InvalidContext) {
   1046   RunTest("Invalid[]", /*expected_classpath_key*/ nullptr, /*expected_success*/ false);
   1047 }
   1048 
   1049 TEST_F(Dex2oatClassLoaderContextTest, EmptyContext) {
   1050   RunTest("PCL[]", kEmptyClassPathKey, /*expected_success*/ true);
   1051 }
   1052 
   1053 TEST_F(Dex2oatClassLoaderContextTest, SpecialContext) {
   1054   RunTest(OatFile::kSpecialSharedLibrary,
   1055           OatFile::kSpecialSharedLibrary,
   1056           /*expected_success*/ true);
   1057 }
   1058 
   1059 TEST_F(Dex2oatClassLoaderContextTest, ContextWithTheSourceDexFiles) {
   1060   std::string context = "PCL[" + GetUsedDexLocation() + "]";
   1061   RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
   1062 }
   1063 
   1064 TEST_F(Dex2oatClassLoaderContextTest, ContextWithOtherDexFiles) {
   1065   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Nested");
   1066 
   1067   std::string context = "PCL[" + dex_files[0]->GetLocation() + "]";
   1068   std::string expected_classpath_key = "PCL[" +
   1069       dex_files[0]->GetLocation() + "*" + std::to_string(dex_files[0]->GetLocationChecksum()) + "]";
   1070   RunTest(context.c_str(), expected_classpath_key.c_str(), true);
   1071 }
   1072 
   1073 TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFiles) {
   1074   std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar";
   1075   Copy(GetStrippedDexSrc1(), stripped_classpath);
   1076 
   1077   std::string context = "PCL[" + stripped_classpath + "]";
   1078   // Expect an empty context because stripped dex files cannot be open.
   1079   RunTest(context.c_str(), kEmptyClassPathKey , /*expected_success*/ true);
   1080 }
   1081 
   1082 TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFilesBackedByOdex) {
   1083   std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar";
   1084   std::string odex_for_classpath = GetOdexDir() + "/stripped_classpath.odex";
   1085 
   1086   Copy(GetDexSrc1(), stripped_classpath);
   1087 
   1088   GenerateOdexForTest(stripped_classpath,
   1089                       odex_for_classpath,
   1090                       CompilerFilter::kQuicken,
   1091                       {},
   1092                       true);
   1093 
   1094   // Strip the dex file
   1095   Copy(GetStrippedDexSrc1(), stripped_classpath);
   1096 
   1097   std::string context = "PCL[" + stripped_classpath + "]";
   1098   std::string expected_classpath_key;
   1099   {
   1100     // Open the oat file to get the expected classpath.
   1101     OatFileAssistant oat_file_assistant(stripped_classpath.c_str(), kRuntimeISA, false);
   1102     std::unique_ptr<OatFile> oat_file(oat_file_assistant.GetBestOatFile());
   1103     std::vector<std::unique_ptr<const DexFile>> oat_dex_files =
   1104         OatFileAssistant::LoadDexFiles(*oat_file, stripped_classpath.c_str());
   1105     expected_classpath_key = "PCL[";
   1106     for (size_t i = 0; i < oat_dex_files.size(); i++) {
   1107       if (i > 0) {
   1108         expected_classpath_key + ":";
   1109       }
   1110       expected_classpath_key += oat_dex_files[i]->GetLocation() + "*" +
   1111           std::to_string(oat_dex_files[i]->GetLocationChecksum());
   1112     }
   1113     expected_classpath_key += "]";
   1114   }
   1115 
   1116   RunTest(context.c_str(),
   1117           expected_classpath_key.c_str(),
   1118           /*expected_success*/ true,
   1119           /*use_second_source*/ true);
   1120 }
   1121 
   1122 TEST_F(Dex2oatClassLoaderContextTest, ContextWithNotExistentDexFiles) {
   1123   std::string context = "PCL[does_not_exists.dex]";
   1124   // Expect an empty context because stripped dex files cannot be open.
   1125   RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
   1126 }
   1127 
   1128 TEST_F(Dex2oatClassLoaderContextTest, ChainContext) {
   1129   std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
   1130   std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
   1131 
   1132   std::string context = "PCL[" + GetTestDexFileName("Nested") + "];" +
   1133       "DLC[" + GetTestDexFileName("MultiDex") + "]";
   1134   std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "];" +
   1135       "DLC[" + CreateClassPathWithChecksums(dex_files2) + "]";
   1136 
   1137   RunTest(context.c_str(), expected_classpath_key.c_str(), true);
   1138 }
   1139 
   1140 class Dex2oatDeterminism : public Dex2oatTest {};
   1141 
   1142 TEST_F(Dex2oatDeterminism, UnloadCompile) {
   1143   if (!kUseReadBarrier &&
   1144       gc::kCollectorTypeDefault != gc::kCollectorTypeCMS &&
   1145       gc::kCollectorTypeDefault != gc::kCollectorTypeMS) {
   1146     LOG(INFO) << "Test requires determinism support.";
   1147     return;
   1148   }
   1149   Runtime* const runtime = Runtime::Current();
   1150   std::string out_dir = GetScratchDir();
   1151   const std::string base_oat_name = out_dir + "/base.oat";
   1152   const std::string base_vdex_name = out_dir + "/base.vdex";
   1153   const std::string unload_oat_name = out_dir + "/unload.oat";
   1154   const std::string unload_vdex_name = out_dir + "/unload.vdex";
   1155   const std::string no_unload_oat_name = out_dir + "/nounload.oat";
   1156   const std::string no_unload_vdex_name = out_dir + "/nounload.vdex";
   1157   const std::string app_image_name = out_dir + "/unload.art";
   1158   std::string error_msg;
   1159   const std::vector<gc::space::ImageSpace*>& spaces = runtime->GetHeap()->GetBootImageSpaces();
   1160   ASSERT_GT(spaces.size(), 0u);
   1161   const std::string image_location = spaces[0]->GetImageLocation();
   1162   // Without passing in an app image, it will unload in between compilations.
   1163   const int res = GenerateOdexForTestWithStatus(
   1164       GetLibCoreDexFileNames(),
   1165       base_oat_name,
   1166       CompilerFilter::Filter::kQuicken,
   1167       &error_msg,
   1168       {"--force-determinism", "--avoid-storing-invocation"});
   1169   EXPECT_EQ(res, 0);
   1170   Copy(base_oat_name, unload_oat_name);
   1171   Copy(base_vdex_name, unload_vdex_name);
   1172   std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str()));
   1173   std::unique_ptr<File> unload_vdex(OS::OpenFileForReading(unload_vdex_name.c_str()));
   1174   ASSERT_TRUE(unload_oat != nullptr);
   1175   ASSERT_TRUE(unload_vdex != nullptr);
   1176   EXPECT_GT(unload_oat->GetLength(), 0u);
   1177   EXPECT_GT(unload_vdex->GetLength(), 0u);
   1178   // Regenerate with an app image to disable the dex2oat unloading and verify that the output is
   1179   // the same.
   1180   const int res2 = GenerateOdexForTestWithStatus(
   1181       GetLibCoreDexFileNames(),
   1182       base_oat_name,
   1183       CompilerFilter::Filter::kQuicken,
   1184       &error_msg,
   1185       {"--force-determinism", "--avoid-storing-invocation", "--app-image-file=" + app_image_name});
   1186   EXPECT_EQ(res2, 0);
   1187   Copy(base_oat_name, no_unload_oat_name);
   1188   Copy(base_vdex_name, no_unload_vdex_name);
   1189   std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str()));
   1190   std::unique_ptr<File> no_unload_vdex(OS::OpenFileForReading(no_unload_vdex_name.c_str()));
   1191   ASSERT_TRUE(no_unload_oat != nullptr);
   1192   ASSERT_TRUE(no_unload_vdex != nullptr);
   1193   EXPECT_GT(no_unload_oat->GetLength(), 0u);
   1194   EXPECT_GT(no_unload_vdex->GetLength(), 0u);
   1195   // Verify that both of the files are the same (odex and vdex).
   1196   EXPECT_EQ(unload_oat->GetLength(), no_unload_oat->GetLength());
   1197   EXPECT_EQ(unload_vdex->GetLength(), no_unload_vdex->GetLength());
   1198   EXPECT_EQ(unload_oat->Compare(no_unload_oat.get()), 0)
   1199       << unload_oat_name << " " << no_unload_oat_name;
   1200   EXPECT_EQ(unload_vdex->Compare(no_unload_vdex.get()), 0)
   1201       << unload_vdex_name << " " << no_unload_vdex_name;
   1202   // App image file.
   1203   std::unique_ptr<File> app_image_file(OS::OpenFileForReading(app_image_name.c_str()));
   1204   ASSERT_TRUE(app_image_file != nullptr);
   1205   EXPECT_GT(app_image_file->GetLength(), 0u);
   1206 }
   1207 
   1208 // Test that dexlayout section info is correctly written to the oat file for profile based
   1209 // compilation.
   1210 TEST_F(Dex2oatTest, LayoutSections) {
   1211   using Hotness = ProfileCompilationInfo::MethodHotness;
   1212   std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
   1213   ScratchFile profile_file;
   1214   // We can only layout method indices with code items, figure out which ones have this property
   1215   // first.
   1216   std::vector<uint16_t> methods;
   1217   {
   1218     const DexFile::TypeId* type_id = dex->FindTypeId("LManyMethods;");
   1219     dex::TypeIndex type_idx = dex->GetIndexForTypeId(*type_id);
   1220     const DexFile::ClassDef* class_def = dex->FindClassDef(type_idx);
   1221     ClassDataItemIterator it(*dex, dex->GetClassData(*class_def));
   1222     it.SkipAllFields();
   1223     std::set<size_t> code_item_offsets;
   1224     for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
   1225       const uint16_t method_idx = it.GetMemberIndex();
   1226       const size_t code_item_offset = it.GetMethodCodeItemOffset();
   1227       if (code_item_offsets.insert(code_item_offset).second) {
   1228         // Unique code item, add the method index.
   1229         methods.push_back(method_idx);
   1230       }
   1231     }
   1232     DCHECK(!it.HasNext());
   1233   }
   1234   ASSERT_GE(methods.size(), 8u);
   1235   std::vector<uint16_t> hot_methods = {methods[1], methods[3], methods[5]};
   1236   std::vector<uint16_t> startup_methods = {methods[1], methods[2], methods[7]};
   1237   std::vector<uint16_t> post_methods = {methods[0], methods[2], methods[6]};
   1238   // Here, we build the profile from the method lists.
   1239   ProfileCompilationInfo info;
   1240   info.AddMethodsForDex(
   1241       static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
   1242       dex.get(),
   1243       hot_methods.begin(),
   1244       hot_methods.end());
   1245   info.AddMethodsForDex(
   1246       Hotness::kFlagStartup,
   1247       dex.get(),
   1248       startup_methods.begin(),
   1249       startup_methods.end());
   1250   info.AddMethodsForDex(
   1251       Hotness::kFlagPostStartup,
   1252       dex.get(),
   1253       post_methods.begin(),
   1254       post_methods.end());
   1255   for (uint16_t id : hot_methods) {
   1256     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot());
   1257     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
   1258   }
   1259   for (uint16_t id : startup_methods) {
   1260     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
   1261   }
   1262   for (uint16_t id : post_methods) {
   1263     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup());
   1264   }
   1265   // Save the profile since we want to use it with dex2oat to produce an oat file.
   1266   ASSERT_TRUE(info.Save(profile_file.GetFd()));
   1267   // Generate a profile based odex.
   1268   const std::string dir = GetScratchDir();
   1269   const std::string oat_filename = dir + "/base.oat";
   1270   const std::string vdex_filename = dir + "/base.vdex";
   1271   std::string error_msg;
   1272   const int res = GenerateOdexForTestWithStatus(
   1273       {dex->GetLocation()},
   1274       oat_filename,
   1275       CompilerFilter::Filter::kQuicken,
   1276       &error_msg,
   1277       {"--profile-file=" + profile_file.GetFilename()});
   1278   EXPECT_EQ(res, 0);
   1279 
   1280   // Open our generated oat file.
   1281   std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_filename.c_str(),
   1282                                                    oat_filename.c_str(),
   1283                                                    nullptr,
   1284                                                    nullptr,
   1285                                                    false,
   1286                                                    /*low_4gb*/false,
   1287                                                    dex->GetLocation().c_str(),
   1288                                                    &error_msg));
   1289   ASSERT_TRUE(odex_file != nullptr);
   1290   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
   1291   ASSERT_EQ(oat_dex_files.size(), 1u);
   1292   // Check that the code sections match what we expect.
   1293   for (const OatDexFile* oat_dex : oat_dex_files) {
   1294     const DexLayoutSections* const sections = oat_dex->GetDexLayoutSections();
   1295     // Testing of logging the sections.
   1296     ASSERT_TRUE(sections != nullptr);
   1297     LOG(INFO) << *sections;
   1298 
   1299     // Load the sections into temporary variables for convenience.
   1300     const DexLayoutSection& code_section =
   1301         sections->sections_[static_cast<size_t>(DexLayoutSections::SectionType::kSectionTypeCode)];
   1302     const DexLayoutSection::Subsection& section_hot_code =
   1303         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeHot)];
   1304     const DexLayoutSection::Subsection& section_sometimes_used =
   1305         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeSometimesUsed)];
   1306     const DexLayoutSection::Subsection& section_startup_only =
   1307         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeStartupOnly)];
   1308     const DexLayoutSection::Subsection& section_unused =
   1309         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeUnused)];
   1310 
   1311     // All the sections should be non-empty.
   1312     EXPECT_GT(section_hot_code.size_, 0u);
   1313     EXPECT_GT(section_sometimes_used.size_, 0u);
   1314     EXPECT_GT(section_startup_only.size_, 0u);
   1315     EXPECT_GT(section_unused.size_, 0u);
   1316 
   1317     // Open the dex file since we need to peek at the code items to verify the layout matches what
   1318     // we expect.
   1319     std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
   1320     ASSERT_TRUE(dex_file != nullptr) << error_msg;
   1321     const DexFile::TypeId* type_id = dex_file->FindTypeId("LManyMethods;");
   1322     ASSERT_TRUE(type_id != nullptr);
   1323     dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
   1324     const DexFile::ClassDef* class_def = dex_file->FindClassDef(type_idx);
   1325     ASSERT_TRUE(class_def != nullptr);
   1326 
   1327     // Count how many code items are for each category, there should be at least one per category.
   1328     size_t hot_count = 0;
   1329     size_t post_startup_count = 0;
   1330     size_t startup_count = 0;
   1331     size_t unused_count = 0;
   1332     // Visit all of the methdos of the main class and cross reference the method indices to their
   1333     // corresponding code item offsets to verify the layout.
   1334     ClassDataItemIterator it(*dex_file, dex_file->GetClassData(*class_def));
   1335     it.SkipAllFields();
   1336     for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
   1337       const size_t method_idx = it.GetMemberIndex();
   1338       const size_t code_item_offset = it.GetMethodCodeItemOffset();
   1339       const bool is_hot = ContainsElement(hot_methods, method_idx);
   1340       const bool is_startup = ContainsElement(startup_methods, method_idx);
   1341       const bool is_post_startup = ContainsElement(post_methods, method_idx);
   1342       if (is_hot) {
   1343         // Hot is highest precedence, check that the hot methods are in the hot section.
   1344         EXPECT_LT(code_item_offset - section_hot_code.offset_, section_hot_code.size_);
   1345         ++hot_count;
   1346       } else if (is_post_startup) {
   1347         // Post startup is sometimes used section.
   1348         EXPECT_LT(code_item_offset - section_sometimes_used.offset_, section_sometimes_used.size_);
   1349         ++post_startup_count;
   1350       } else if (is_startup) {
   1351         // Startup at this point means not hot or post startup, these must be startup only then.
   1352         EXPECT_LT(code_item_offset - section_startup_only.offset_, section_startup_only.size_);
   1353         ++startup_count;
   1354       } else {
   1355         // If no flags are set, the method should be unused.
   1356         EXPECT_LT(code_item_offset - section_unused.offset_, section_unused.size_);
   1357         ++unused_count;
   1358       }
   1359     }
   1360     DCHECK(!it.HasNext());
   1361     EXPECT_GT(hot_count, 0u);
   1362     EXPECT_GT(post_startup_count, 0u);
   1363     EXPECT_GT(startup_count, 0u);
   1364     EXPECT_GT(unused_count, 0u);
   1365   }
   1366 }
   1367 
   1368 }  // namespace art
   1369