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 "dex_file-inl.h"
     32 #include "dex2oat_environment_test.h"
     33 #include "dex2oat_return_codes.h"
     34 #include "jit/profile_compilation_info.h"
     35 #include "oat.h"
     36 #include "oat_file.h"
     37 #include "utils.h"
     38 
     39 namespace art {
     40 
     41 using android::base::StringPrintf;
     42 
     43 class Dex2oatTest : public Dex2oatEnvironmentTest {
     44  public:
     45   virtual void TearDown() OVERRIDE {
     46     Dex2oatEnvironmentTest::TearDown();
     47 
     48     output_ = "";
     49     error_msg_ = "";
     50     success_ = false;
     51   }
     52 
     53  protected:
     54   int GenerateOdexForTestWithStatus(const std::string& dex_location,
     55                                     const std::string& odex_location,
     56                                     CompilerFilter::Filter filter,
     57                                     std::string* error_msg,
     58                                     const std::vector<std::string>& extra_args = {},
     59                                     bool use_fd = false) {
     60     std::unique_ptr<File> oat_file;
     61     std::vector<std::string> args;
     62     args.push_back("--dex-file=" + dex_location);
     63     if (use_fd) {
     64       oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
     65       CHECK(oat_file != nullptr) << odex_location;
     66       args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
     67       args.push_back("--oat-location=" + odex_location);
     68     } else {
     69       args.push_back("--oat-file=" + odex_location);
     70     }
     71     args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
     72     args.push_back("--runtime-arg");
     73     args.push_back("-Xnorelocate");
     74 
     75     args.insert(args.end(), extra_args.begin(), extra_args.end());
     76 
     77     int status = Dex2Oat(args, error_msg);
     78     if (oat_file != nullptr) {
     79       CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
     80     }
     81     return status;
     82   }
     83 
     84   void GenerateOdexForTest(const std::string& dex_location,
     85                            const std::string& odex_location,
     86                            CompilerFilter::Filter filter,
     87                            const std::vector<std::string>& extra_args = {},
     88                            bool expect_success = true,
     89                            bool use_fd = false) {
     90     std::string error_msg;
     91     int status = GenerateOdexForTestWithStatus(dex_location,
     92                                                odex_location,
     93                                                filter,
     94                                                &error_msg,
     95                                                extra_args,
     96                                                use_fd);
     97     bool success = (status == 0);
     98     if (expect_success) {
     99       ASSERT_TRUE(success) << error_msg << std::endl << output_;
    100 
    101       // Verify the odex file was generated as expected.
    102       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    103                                                        odex_location.c_str(),
    104                                                        nullptr,
    105                                                        nullptr,
    106                                                        false,
    107                                                        /*low_4gb*/false,
    108                                                        dex_location.c_str(),
    109                                                        &error_msg));
    110       ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    111 
    112       CheckFilter(filter, odex_file->GetCompilerFilter());
    113     } else {
    114       ASSERT_FALSE(success) << output_;
    115 
    116       error_msg_ = error_msg;
    117 
    118       // Verify there's no loadable odex file.
    119       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    120                                                        odex_location.c_str(),
    121                                                        nullptr,
    122                                                        nullptr,
    123                                                        false,
    124                                                        /*low_4gb*/false,
    125                                                        dex_location.c_str(),
    126                                                        &error_msg));
    127       ASSERT_TRUE(odex_file.get() == nullptr);
    128     }
    129   }
    130 
    131   // Check the input compiler filter against the generated oat file's filter. Mayb be overridden
    132   // in subclasses when equality is not expected.
    133   virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
    134     EXPECT_EQ(expected, actual);
    135   }
    136 
    137   int Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
    138     Runtime* runtime = Runtime::Current();
    139 
    140     const std::vector<gc::space::ImageSpace*>& image_spaces =
    141         runtime->GetHeap()->GetBootImageSpaces();
    142     if (image_spaces.empty()) {
    143       *error_msg = "No image location found for Dex2Oat.";
    144       return false;
    145     }
    146     std::string image_location = image_spaces[0]->GetImageLocation();
    147 
    148     std::vector<std::string> argv;
    149     argv.push_back(runtime->GetCompilerExecutable());
    150     argv.push_back("--runtime-arg");
    151     argv.push_back("-classpath");
    152     argv.push_back("--runtime-arg");
    153     std::string class_path = runtime->GetClassPathString();
    154     if (class_path == "") {
    155       class_path = OatFile::kSpecialSharedLibrary;
    156     }
    157     argv.push_back(class_path);
    158     if (runtime->IsJavaDebuggable()) {
    159       argv.push_back("--debuggable");
    160     }
    161     runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
    162 
    163     if (!runtime->IsVerificationEnabled()) {
    164       argv.push_back("--compiler-filter=assume-verified");
    165     }
    166 
    167     if (runtime->MustRelocateIfPossible()) {
    168       argv.push_back("--runtime-arg");
    169       argv.push_back("-Xrelocate");
    170     } else {
    171       argv.push_back("--runtime-arg");
    172       argv.push_back("-Xnorelocate");
    173     }
    174 
    175     if (!kIsTargetBuild) {
    176       argv.push_back("--host");
    177     }
    178 
    179     argv.push_back("--boot-image=" + image_location);
    180 
    181     std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
    182     argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
    183 
    184     argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
    185 
    186     // We must set --android-root.
    187     const char* android_root = getenv("ANDROID_ROOT");
    188     CHECK(android_root != nullptr);
    189     argv.push_back("--android-root=" + std::string(android_root));
    190 
    191     int link[2];
    192 
    193     if (pipe(link) == -1) {
    194       return false;
    195     }
    196 
    197     pid_t pid = fork();
    198     if (pid == -1) {
    199       return false;
    200     }
    201 
    202     if (pid == 0) {
    203       // We need dex2oat to actually log things.
    204       setenv("ANDROID_LOG_TAGS", "*:d", 1);
    205       dup2(link[1], STDERR_FILENO);
    206       close(link[0]);
    207       close(link[1]);
    208       std::vector<const char*> c_args;
    209       for (const std::string& str : argv) {
    210         c_args.push_back(str.c_str());
    211       }
    212       c_args.push_back(nullptr);
    213       execv(c_args[0], const_cast<char* const*>(c_args.data()));
    214       exit(1);
    215       UNREACHABLE();
    216     } else {
    217       close(link[1]);
    218       char buffer[128];
    219       memset(buffer, 0, 128);
    220       ssize_t bytes_read = 0;
    221 
    222       while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
    223         output_ += std::string(buffer, bytes_read);
    224       }
    225       close(link[0]);
    226       int status = -1;
    227       if (waitpid(pid, &status, 0) != -1) {
    228         success_ = (status == 0);
    229       }
    230       return status;
    231     }
    232   }
    233 
    234   std::string output_ = "";
    235   std::string error_msg_ = "";
    236   bool success_ = false;
    237 };
    238 
    239 class Dex2oatSwapTest : public Dex2oatTest {
    240  protected:
    241   void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
    242     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
    243     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
    244 
    245     Copy(GetTestDexFileName(), dex_location);
    246 
    247     std::vector<std::string> copy(extra_args);
    248 
    249     std::unique_ptr<ScratchFile> sf;
    250     if (use_fd) {
    251       sf.reset(new ScratchFile());
    252       copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
    253     } else {
    254       std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
    255       copy.push_back("--swap-file=" + swap_location);
    256     }
    257     GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
    258 
    259     CheckValidity();
    260     ASSERT_TRUE(success_);
    261     CheckResult(expect_use);
    262   }
    263 
    264   virtual std::string GetTestDexFileName() {
    265     return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps");
    266   }
    267 
    268   virtual void CheckResult(bool expect_use) {
    269     if (kIsTargetBuild) {
    270       CheckTargetResult(expect_use);
    271     } else {
    272       CheckHostResult(expect_use);
    273     }
    274   }
    275 
    276   virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
    277     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
    278     //       something for variants with file descriptor where we can control the lifetime of
    279     //       the swap file and thus take a look at it.
    280   }
    281 
    282   virtual void CheckHostResult(bool expect_use) {
    283     if (!kIsTargetBuild) {
    284       if (expect_use) {
    285         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
    286             << output_;
    287       } else {
    288         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
    289             << output_;
    290       }
    291     }
    292   }
    293 
    294   // Check whether the dex2oat run was really successful.
    295   virtual void CheckValidity() {
    296     if (kIsTargetBuild) {
    297       CheckTargetValidity();
    298     } else {
    299       CheckHostValidity();
    300     }
    301   }
    302 
    303   virtual void CheckTargetValidity() {
    304     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
    305     //       something for variants with file descriptor where we can control the lifetime of
    306     //       the swap file and thus take a look at it.
    307   }
    308 
    309   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
    310   virtual void CheckHostValidity() {
    311     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
    312   }
    313 };
    314 
    315 TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
    316   RunTest(false /* use_fd */, false /* expect_use */);
    317   RunTest(true /* use_fd */, false /* expect_use */);
    318 }
    319 
    320 TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
    321   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
    322   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
    323 }
    324 
    325 TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
    326   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
    327   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
    328 }
    329 
    330 TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
    331   RunTest(false /* use_fd */,
    332           true /* expect_use */,
    333           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
    334   RunTest(true /* use_fd */,
    335           true /* expect_use */,
    336           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
    337 }
    338 
    339 class Dex2oatSwapUseTest : public Dex2oatSwapTest {
    340  protected:
    341   void CheckHostResult(bool expect_use) OVERRIDE {
    342     if (!kIsTargetBuild) {
    343       if (expect_use) {
    344         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
    345             << output_;
    346       } else {
    347         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
    348             << output_;
    349       }
    350     }
    351   }
    352 
    353   std::string GetTestDexFileName() OVERRIDE {
    354     // Use Statics as it has a handful of functions.
    355     return CommonRuntimeTest::GetTestDexFileName("Statics");
    356   }
    357 
    358   void GrabResult1() {
    359     if (!kIsTargetBuild) {
    360       native_alloc_1_ = ParseNativeAlloc();
    361       swap_1_ = ParseSwap(false /* expected */);
    362     } else {
    363       native_alloc_1_ = std::numeric_limits<size_t>::max();
    364       swap_1_ = 0;
    365     }
    366   }
    367 
    368   void GrabResult2() {
    369     if (!kIsTargetBuild) {
    370       native_alloc_2_ = ParseNativeAlloc();
    371       swap_2_ = ParseSwap(true /* expected */);
    372     } else {
    373       native_alloc_2_ = 0;
    374       swap_2_ = std::numeric_limits<size_t>::max();
    375     }
    376   }
    377 
    378  private:
    379   size_t ParseNativeAlloc() {
    380     std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)");
    381     std::smatch native_alloc_match;
    382     bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex);
    383     if (!found) {
    384       EXPECT_TRUE(found);
    385       return 0;
    386     }
    387     if (native_alloc_match.size() != 2U) {
    388       EXPECT_EQ(native_alloc_match.size(), 2U);
    389       return 0;
    390     }
    391 
    392     std::istringstream stream(native_alloc_match[1].str());
    393     size_t value;
    394     stream >> value;
    395 
    396     return value;
    397   }
    398 
    399   size_t ParseSwap(bool expected) {
    400     std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)");
    401     std::smatch swap_match;
    402     bool found = std::regex_search(output_, swap_match, swap_regex);
    403     if (found != expected) {
    404       EXPECT_EQ(expected, found);
    405       return 0;
    406     }
    407 
    408     if (!found) {
    409       return 0;
    410     }
    411 
    412     if (swap_match.size() != 2U) {
    413       EXPECT_EQ(swap_match.size(), 2U);
    414       return 0;
    415     }
    416 
    417     std::istringstream stream(swap_match[1].str());
    418     size_t value;
    419     stream >> value;
    420 
    421     return value;
    422   }
    423 
    424  protected:
    425   size_t native_alloc_1_;
    426   size_t native_alloc_2_;
    427 
    428   size_t swap_1_;
    429   size_t swap_2_;
    430 };
    431 
    432 TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
    433   // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
    434   // hold true on some x86 systems; disable this test while we
    435   // investigate (b/29259363).
    436   TEST_DISABLED_FOR_X86();
    437 
    438   RunTest(false /* use_fd */,
    439           false /* expect_use */);
    440   GrabResult1();
    441   std::string output_1 = output_;
    442 
    443   output_ = "";
    444 
    445   RunTest(false /* use_fd */,
    446           true /* expect_use */,
    447           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
    448   GrabResult2();
    449   std::string output_2 = output_;
    450 
    451   if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) {
    452     EXPECT_LT(native_alloc_2_, native_alloc_1_);
    453     EXPECT_LT(swap_1_, swap_2_);
    454 
    455     LOG(ERROR) << output_1;
    456     LOG(ERROR) << output_2;
    457   }
    458 }
    459 
    460 class Dex2oatVeryLargeTest : public Dex2oatTest {
    461  protected:
    462   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
    463                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
    464     // Ignore, we'll do our own checks.
    465   }
    466 
    467   void RunTest(CompilerFilter::Filter filter,
    468                bool expect_large,
    469                const std::vector<std::string>& extra_args = {}) {
    470     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
    471     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
    472 
    473     Copy(GetDexSrc1(), dex_location);
    474 
    475     GenerateOdexForTest(dex_location, odex_location, filter, extra_args);
    476 
    477     CheckValidity();
    478     ASSERT_TRUE(success_);
    479     CheckResult(dex_location, odex_location, filter, expect_large);
    480   }
    481 
    482   void CheckResult(const std::string& dex_location,
    483                    const std::string& odex_location,
    484                    CompilerFilter::Filter filter,
    485                    bool expect_large) {
    486     // Host/target independent checks.
    487     std::string error_msg;
    488     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    489                                                      odex_location.c_str(),
    490                                                      nullptr,
    491                                                      nullptr,
    492                                                      false,
    493                                                      /*low_4gb*/false,
    494                                                      dex_location.c_str(),
    495                                                      &error_msg));
    496     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    497     if (expect_large) {
    498       // Note: we cannot check the following:
    499       //   EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
    500       //                                          odex_file->GetCompilerFilter()));
    501       // The reason is that the filter override currently happens when the dex files are
    502       // loaded in dex2oat, which is after the oat file has been started. Thus, the header
    503       // store cannot be changed, and the original filter is set in stone.
    504 
    505       for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
    506         std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
    507         ASSERT_TRUE(dex_file != nullptr);
    508         uint32_t class_def_count = dex_file->NumClassDefs();
    509         ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
    510         for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
    511           OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    512           EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
    513         }
    514       }
    515 
    516       // If the input filter was "below," it should have been used.
    517       if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract, filter)) {
    518         EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
    519       }
    520     } else {
    521       EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
    522     }
    523 
    524     // Host/target dependent checks.
    525     if (kIsTargetBuild) {
    526       CheckTargetResult(expect_large);
    527     } else {
    528       CheckHostResult(expect_large);
    529     }
    530   }
    531 
    532   void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) {
    533     // TODO: Ignore for now. May do something for fd things.
    534   }
    535 
    536   void CheckHostResult(bool expect_large) {
    537     if (!kIsTargetBuild) {
    538       if (expect_large) {
    539         EXPECT_NE(output_.find("Very large app, downgrading to extract."),
    540                   std::string::npos)
    541             << output_;
    542       } else {
    543         EXPECT_EQ(output_.find("Very large app, downgrading to extract."),
    544                   std::string::npos)
    545             << output_;
    546       }
    547     }
    548   }
    549 
    550   // Check whether the dex2oat run was really successful.
    551   void CheckValidity() {
    552     if (kIsTargetBuild) {
    553       CheckTargetValidity();
    554     } else {
    555       CheckHostValidity();
    556     }
    557   }
    558 
    559   void CheckTargetValidity() {
    560     // TODO: Ignore for now.
    561   }
    562 
    563   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
    564   void CheckHostValidity() {
    565     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
    566   }
    567 };
    568 
    569 TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
    570   RunTest(CompilerFilter::kAssumeVerified, false);
    571   RunTest(CompilerFilter::kExtract, false);
    572   RunTest(CompilerFilter::kQuicken, false);
    573   RunTest(CompilerFilter::kSpeed, false);
    574 
    575   RunTest(CompilerFilter::kAssumeVerified, false, { "--very-large-app-threshold=1000000" });
    576   RunTest(CompilerFilter::kExtract, false, { "--very-large-app-threshold=1000000" });
    577   RunTest(CompilerFilter::kQuicken, false, { "--very-large-app-threshold=1000000" });
    578   RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
    579 }
    580 
    581 TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
    582   RunTest(CompilerFilter::kAssumeVerified, false, { "--very-large-app-threshold=100" });
    583   RunTest(CompilerFilter::kExtract, false, { "--very-large-app-threshold=100" });
    584   RunTest(CompilerFilter::kQuicken, true, { "--very-large-app-threshold=100" });
    585   RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
    586 }
    587 
    588 // Regressin test for b/35665292.
    589 TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) {
    590   // Test that dex2oat doesn't crash with speed-profile but no input profile.
    591   RunTest(CompilerFilter::kSpeedProfile, false);
    592 }
    593 
    594 class Dex2oatLayoutTest : public Dex2oatTest {
    595  protected:
    596   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
    597                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
    598     // Ignore, we'll do our own checks.
    599   }
    600 
    601   // Emits a profile with a single dex file with the given location and a single class index of 1.
    602   void GenerateProfile(const std::string& test_profile,
    603                        const std::string& dex_location,
    604                        size_t num_classes,
    605                        uint32_t checksum) {
    606     int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
    607     CHECK_GE(profile_test_fd, 0);
    608 
    609     ProfileCompilationInfo info;
    610     std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location);
    611     for (size_t i = 0; i < num_classes; ++i) {
    612       info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i));
    613     }
    614     bool result = info.Save(profile_test_fd);
    615     close(profile_test_fd);
    616     ASSERT_TRUE(result);
    617   }
    618 
    619   void CompileProfileOdex(const std::string& dex_location,
    620                           const std::string& odex_location,
    621                           const std::string& app_image_file_name,
    622                           bool use_fd,
    623                           size_t num_profile_classes,
    624                           const std::vector<std::string>& extra_args = {},
    625                           bool expect_success = true) {
    626     const std::string profile_location = GetScratchDir() + "/primary.prof";
    627     const char* location = dex_location.c_str();
    628     std::string error_msg;
    629     std::vector<std::unique_ptr<const DexFile>> dex_files;
    630     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
    631     EXPECT_EQ(dex_files.size(), 1U);
    632     std::unique_ptr<const DexFile>& dex_file = dex_files[0];
    633     GenerateProfile(profile_location,
    634                     dex_location,
    635                     num_profile_classes,
    636                     dex_file->GetLocationChecksum());
    637     std::vector<std::string> copy(extra_args);
    638     copy.push_back("--profile-file=" + profile_location);
    639     std::unique_ptr<File> app_image_file;
    640     if (!app_image_file_name.empty()) {
    641       if (use_fd) {
    642         app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str()));
    643         copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd()));
    644       } else {
    645         copy.push_back("--app-image-file=" + app_image_file_name);
    646       }
    647     }
    648     GenerateOdexForTest(dex_location,
    649                         odex_location,
    650                         CompilerFilter::kSpeedProfile,
    651                         copy,
    652                         expect_success,
    653                         use_fd);
    654     if (app_image_file != nullptr) {
    655       ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
    656     }
    657   }
    658 
    659   uint64_t GetImageSize(const std::string& image_file_name) {
    660     EXPECT_FALSE(image_file_name.empty());
    661     std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
    662     CHECK(file != nullptr);
    663     ImageHeader image_header;
    664     const bool success = file->ReadFully(&image_header, sizeof(image_header));
    665     CHECK(success);
    666     CHECK(image_header.IsValid());
    667     ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
    668     return image_header.GetImageSize();
    669   }
    670 
    671   void RunTest(bool app_image) {
    672     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
    673     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
    674     std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): "";
    675     Copy(GetDexSrc2(), dex_location);
    676 
    677     uint64_t image_file_empty_profile = 0;
    678     if (app_image) {
    679       CompileProfileOdex(dex_location,
    680                          odex_location,
    681                          app_image_file,
    682                          /* use_fd */ false,
    683                          /* num_profile_classes */ 0);
    684       CheckValidity();
    685       ASSERT_TRUE(success_);
    686       // Don't check the result since CheckResult relies on the class being in the profile.
    687       image_file_empty_profile = GetImageSize(app_image_file);
    688       EXPECT_GT(image_file_empty_profile, 0u);
    689     }
    690 
    691     // Small profile.
    692     CompileProfileOdex(dex_location,
    693                        odex_location,
    694                        app_image_file,
    695                        /* use_fd */ false,
    696                        /* num_profile_classes */ 1);
    697     CheckValidity();
    698     ASSERT_TRUE(success_);
    699     CheckResult(dex_location, odex_location, app_image_file);
    700 
    701     if (app_image) {
    702       // Test that the profile made a difference by adding more classes.
    703       const uint64_t image_file_small_profile = GetImageSize(app_image_file);
    704       CHECK_LT(image_file_empty_profile, image_file_small_profile);
    705     }
    706   }
    707 
    708   void RunTestVDex() {
    709     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
    710     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
    711     std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
    712     std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art";
    713     Copy(GetDexSrc2(), dex_location);
    714 
    715     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
    716     CHECK(vdex_file1 != nullptr) << vdex_location;
    717     ScratchFile vdex_file2;
    718     {
    719       std::string input_vdex = "--input-vdex-fd=-1";
    720       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
    721       CompileProfileOdex(dex_location,
    722                          odex_location,
    723                          app_image_file_name,
    724                          /* use_fd */ true,
    725                          /* num_profile_classes */ 1,
    726                          { input_vdex, output_vdex });
    727       EXPECT_GT(vdex_file1->GetLength(), 0u);
    728     }
    729     {
    730       // Test that vdex and dexlayout fail gracefully.
    731       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
    732       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
    733       CompileProfileOdex(dex_location,
    734                          odex_location,
    735                          app_image_file_name,
    736                          /* use_fd */ true,
    737                          /* num_profile_classes */ 1,
    738                          { input_vdex, output_vdex },
    739                          /* expect_success */ true);
    740       EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
    741     }
    742     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
    743     CheckValidity();
    744     ASSERT_TRUE(success_);
    745   }
    746 
    747   void CheckResult(const std::string& dex_location,
    748                    const std::string& odex_location,
    749                    const std::string& app_image_file_name) {
    750     // Host/target independent checks.
    751     std::string error_msg;
    752     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
    753                                                      odex_location.c_str(),
    754                                                      nullptr,
    755                                                      nullptr,
    756                                                      false,
    757                                                      /*low_4gb*/false,
    758                                                      dex_location.c_str(),
    759                                                      &error_msg));
    760     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
    761 
    762     const char* location = dex_location.c_str();
    763     std::vector<std::unique_ptr<const DexFile>> dex_files;
    764     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
    765     EXPECT_EQ(dex_files.size(), 1U);
    766     std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
    767 
    768     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
    769       std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
    770       ASSERT_TRUE(new_dex_file != nullptr);
    771       uint32_t class_def_count = new_dex_file->NumClassDefs();
    772       ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
    773       ASSERT_GE(class_def_count, 2U);
    774 
    775       // The new layout swaps the classes at indexes 0 and 1.
    776       std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
    777       std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
    778       std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
    779       std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
    780       EXPECT_EQ(old_class0, new_class1);
    781       EXPECT_EQ(old_class1, new_class0);
    782     }
    783 
    784     EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
    785 
    786     if (!app_image_file_name.empty()) {
    787       // Go peek at the image header to make sure it was large enough to contain the class.
    788       std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str()));
    789       ImageHeader image_header;
    790       bool success = file->ReadFully(&image_header, sizeof(image_header));
    791       ASSERT_TRUE(success);
    792       ASSERT_TRUE(image_header.IsValid());
    793       EXPECT_GT(image_header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u);
    794     }
    795   }
    796 
    797   // Check whether the dex2oat run was really successful.
    798   void CheckValidity() {
    799     if (kIsTargetBuild) {
    800       CheckTargetValidity();
    801     } else {
    802       CheckHostValidity();
    803     }
    804   }
    805 
    806   void CheckTargetValidity() {
    807     // TODO: Ignore for now.
    808   }
    809 
    810   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
    811   void CheckHostValidity() {
    812     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
    813   }
    814 };
    815 
    816 TEST_F(Dex2oatLayoutTest, TestLayout) {
    817   RunTest(/* app-image */ false);
    818 }
    819 
    820 TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) {
    821   RunTest(/* app-image */ true);
    822 }
    823 
    824 TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
    825   RunTestVDex();
    826 }
    827 
    828 class Dex2oatWatchdogTest : public Dex2oatTest {
    829  protected:
    830   void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {
    831     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
    832     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
    833 
    834     Copy(GetTestDexFileName(), dex_location);
    835 
    836     std::vector<std::string> copy(extra_args);
    837 
    838     std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
    839     copy.push_back("--swap-file=" + swap_location);
    840     GenerateOdexForTest(dex_location,
    841                         odex_location,
    842                         CompilerFilter::kSpeed,
    843                         copy,
    844                         expect_success);
    845   }
    846 
    847   std::string GetTestDexFileName() {
    848     return GetDexSrc1();
    849   }
    850 };
    851 
    852 TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
    853   // Check with default.
    854   RunTest(true);
    855 
    856   // Check with ten minutes.
    857   RunTest(true, { "--watchdog-timeout=600000" });
    858 }
    859 
    860 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
    861   // Check with ten milliseconds.
    862   RunTest(false, { "--watchdog-timeout=10" });
    863 }
    864 
    865 class Dex2oatReturnCodeTest : public Dex2oatTest {
    866  protected:
    867   int RunTest(const std::vector<std::string>& extra_args = {}) {
    868     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
    869     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
    870 
    871     Copy(GetTestDexFileName(), dex_location);
    872 
    873     std::string error_msg;
    874     return GenerateOdexForTestWithStatus(dex_location,
    875                                          odex_location,
    876                                          CompilerFilter::kSpeed,
    877                                          &error_msg,
    878                                          extra_args);
    879   }
    880 
    881   std::string GetTestDexFileName() {
    882     return GetDexSrc1();
    883   }
    884 };
    885 
    886 TEST_F(Dex2oatReturnCodeTest, TestCreateRuntime) {
    887   int status = RunTest({ "--boot-image=/this/does/not/exist/yolo.oat" });
    888   EXPECT_EQ(static_cast<int>(dex2oat::ReturnCode::kCreateRuntime), WEXITSTATUS(status)) << output_;
    889 }
    890 
    891 }  // namespace art
    892