Home | History | Annotate | Download | only in dexoptanalyzer
      1 /*
      2  * Copyright (C) 2017 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 <gtest/gtest.h>
     18 
     19 #include "arch/instruction_set.h"
     20 #include "compiler_filter.h"
     21 #include "dexopt_test.h"
     22 
     23 namespace art {
     24 
     25 class DexoptAnalyzerTest : public DexoptTest {
     26  protected:
     27   std::string GetDexoptAnalyzerCmd() {
     28     std::string file_path = GetTestAndroidRoot();
     29     file_path += "/bin/dexoptanalyzer";
     30     if (kIsDebugBuild) {
     31       file_path += "d";
     32     }
     33     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
     34     return file_path;
     35   }
     36 
     37   int Analyze(const std::string& dex_file,
     38               CompilerFilter::Filter compiler_filter,
     39               bool assume_profile_changed) {
     40     std::string dexoptanalyzer_cmd = GetDexoptAnalyzerCmd();
     41     std::vector<std::string> argv_str;
     42     argv_str.push_back(dexoptanalyzer_cmd);
     43     argv_str.push_back("--dex-file=" + dex_file);
     44     argv_str.push_back("--isa=" + std::string(GetInstructionSetString(kRuntimeISA)));
     45     argv_str.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(compiler_filter));
     46     if (assume_profile_changed) {
     47       argv_str.push_back("--assume-profile-changed");
     48     }
     49     argv_str.push_back("--image=" + GetImageLocation());
     50     argv_str.push_back("--android-data=" + android_data_);
     51 
     52     std::string error;
     53     return ExecAndReturnCode(argv_str, &error);
     54   }
     55 
     56   int DexoptanalyzerToOatFileAssistant(int dexoptanalyzerResult) {
     57     switch (dexoptanalyzerResult) {
     58       case 0: return OatFileAssistant::kNoDexOptNeeded;
     59       case 1: return OatFileAssistant::kDex2OatFromScratch;
     60       case 2: return OatFileAssistant::kDex2OatForBootImage;
     61       case 3: return OatFileAssistant::kDex2OatForFilter;
     62       case 4: return OatFileAssistant::kDex2OatForRelocation;
     63       case 5: return -OatFileAssistant::kDex2OatForBootImage;
     64       case 6: return -OatFileAssistant::kDex2OatForFilter;
     65       case 7: return -OatFileAssistant::kDex2OatForRelocation;
     66       default: return dexoptanalyzerResult;
     67     }
     68   }
     69 
     70   // Verify that the output of dexoptanalyzer for the given arguments is the same
     71   // as the output of OatFileAssistant::GetDexOptNeeded.
     72   void Verify(const std::string& dex_file,
     73               CompilerFilter::Filter compiler_filter,
     74               bool assume_profile_changed = false,
     75               bool downgrade = false) {
     76     int dexoptanalyzerResult = Analyze(dex_file, compiler_filter, assume_profile_changed);
     77     dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
     78     OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable*/ false);
     79     int assistantResult = oat_file_assistant.GetDexOptNeeded(
     80         compiler_filter, assume_profile_changed, downgrade);
     81     EXPECT_EQ(assistantResult, dexoptanalyzerResult);
     82   }
     83 };
     84 
     85 // The tests below exercise the same test case from oat_file_assistant_test.cc.
     86 
     87 // Case: We have a DEX file, but no OAT file for it.
     88 TEST_F(DexoptAnalyzerTest, DexNoOat) {
     89   std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
     90   Copy(GetDexSrc1(), dex_location);
     91 
     92   Verify(dex_location, CompilerFilter::kSpeed);
     93   Verify(dex_location, CompilerFilter::kExtract);
     94   Verify(dex_location, CompilerFilter::kQuicken);
     95   Verify(dex_location, CompilerFilter::kSpeedProfile);
     96 }
     97 
     98 // Case: We have a DEX file and up-to-date OAT file for it.
     99 TEST_F(DexoptAnalyzerTest, OatUpToDate) {
    100   std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
    101   Copy(GetDexSrc1(), dex_location);
    102   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
    103 
    104   Verify(dex_location, CompilerFilter::kSpeed);
    105   Verify(dex_location, CompilerFilter::kQuicken);
    106   Verify(dex_location, CompilerFilter::kExtract);
    107   Verify(dex_location, CompilerFilter::kEverything);
    108 }
    109 
    110 // Case: We have a DEX file and speed-profile OAT file for it.
    111 TEST_F(DexoptAnalyzerTest, ProfileOatUpToDate) {
    112   std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar";
    113   Copy(GetDexSrc1(), dex_location);
    114   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
    115 
    116   Verify(dex_location, CompilerFilter::kSpeedProfile, false);
    117   Verify(dex_location, CompilerFilter::kQuicken, false);
    118   Verify(dex_location, CompilerFilter::kSpeedProfile, true);
    119   Verify(dex_location, CompilerFilter::kQuicken, true);
    120 }
    121 
    122 TEST_F(DexoptAnalyzerTest, Downgrade) {
    123   std::string dex_location = GetScratchDir() + "/Downgrade.jar";
    124   Copy(GetDexSrc1(), dex_location);
    125   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken);
    126 
    127   Verify(dex_location, CompilerFilter::kSpeedProfile, false, true);
    128   Verify(dex_location, CompilerFilter::kQuicken, false, true);
    129   Verify(dex_location, CompilerFilter::kVerify, false, true);
    130 }
    131 
    132 // Case: We have a MultiDEX file and up-to-date OAT file for it.
    133 TEST_F(DexoptAnalyzerTest, MultiDexOatUpToDate) {
    134   std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
    135   Copy(GetMultiDexSrc1(), dex_location);
    136   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
    137 
    138   Verify(dex_location, CompilerFilter::kSpeed, false);
    139 }
    140 
    141 // Case: We have a MultiDEX file where the secondary dex file is out of date.
    142 TEST_F(DexoptAnalyzerTest, MultiDexSecondaryOutOfDate) {
    143   std::string dex_location = GetScratchDir() + "/MultiDexSecondaryOutOfDate.jar";
    144 
    145   // Compile code for GetMultiDexSrc1.
    146   Copy(GetMultiDexSrc1(), dex_location);
    147   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
    148 
    149   // Now overwrite the dex file with GetMultiDexSrc2 so the secondary checksum
    150   // is out of date.
    151   Copy(GetMultiDexSrc2(), dex_location);
    152 
    153   Verify(dex_location, CompilerFilter::kSpeed, false);
    154 }
    155 
    156 
    157 // Case: We have a DEX file and an OAT file out of date with respect to the
    158 // dex checksum.
    159 TEST_F(DexoptAnalyzerTest, OatDexOutOfDate) {
    160   std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
    161 
    162   // We create a dex, generate an oat for it, then overwrite the dex with a
    163   // different dex to make the oat out of date.
    164   Copy(GetDexSrc1(), dex_location);
    165   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
    166   Copy(GetDexSrc2(), dex_location);
    167 
    168   Verify(dex_location, CompilerFilter::kExtract);
    169   Verify(dex_location, CompilerFilter::kSpeed);
    170 }
    171 
    172 // Case: We have a DEX file and an OAT file out of date with respect to the
    173 // boot image.
    174 TEST_F(DexoptAnalyzerTest, OatImageOutOfDate) {
    175   std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
    176 
    177   Copy(GetDexSrc1(), dex_location);
    178   GenerateOatForTest(dex_location.c_str(),
    179                      CompilerFilter::kSpeed,
    180                      /*relocate*/true,
    181                      /*pic*/false,
    182                      /*with_alternate_image*/true);
    183 
    184   Verify(dex_location, CompilerFilter::kExtract);
    185   Verify(dex_location, CompilerFilter::kQuicken);
    186   Verify(dex_location, CompilerFilter::kSpeed);
    187 }
    188 
    189 // Case: We have a DEX file and a verify-at-runtime OAT file out of date with
    190 // respect to the boot image.
    191 // It shouldn't matter that the OAT file is out of date, because it is
    192 // verify-at-runtime.
    193 TEST_F(DexoptAnalyzerTest, OatVerifyAtRuntimeImageOutOfDate) {
    194   std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar";
    195 
    196   Copy(GetDexSrc1(), dex_location);
    197   GenerateOatForTest(dex_location.c_str(),
    198                      CompilerFilter::kExtract,
    199                      /*relocate*/true,
    200                      /*pic*/false,
    201                      /*with_alternate_image*/true);
    202 
    203   Verify(dex_location, CompilerFilter::kExtract);
    204   Verify(dex_location, CompilerFilter::kQuicken);
    205 }
    206 
    207 // Case: We have a DEX file and an ODEX file, but no OAT file.
    208 TEST_F(DexoptAnalyzerTest, DexOdexNoOat) {
    209   std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
    210   std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
    211 
    212   Copy(GetDexSrc1(), dex_location);
    213   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
    214 
    215   Verify(dex_location, CompilerFilter::kExtract);
    216   Verify(dex_location, CompilerFilter::kSpeed);
    217 }
    218 
    219 // Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file.
    220 TEST_F(DexoptAnalyzerTest, StrippedDexOdexNoOat) {
    221   std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
    222   std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
    223 
    224   Copy(GetDexSrc1(), dex_location);
    225   GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
    226 
    227   // Strip the dex file
    228   Copy(GetStrippedDexSrc1(), dex_location);
    229 
    230   Verify(dex_location, CompilerFilter::kSpeed);
    231 }
    232 
    233 // Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file.
    234 TEST_F(DexoptAnalyzerTest, StrippedDexOdexOat) {
    235   std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
    236   std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
    237 
    238   // Create the oat file from a different dex file so it looks out of date.
    239   Copy(GetDexSrc2(), dex_location);
    240   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
    241 
    242   // Create the odex file
    243   Copy(GetDexSrc1(), dex_location);
    244   GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
    245 
    246   // Strip the dex file.
    247   Copy(GetStrippedDexSrc1(), dex_location);
    248 
    249   Verify(dex_location, CompilerFilter::kExtract);
    250   Verify(dex_location, CompilerFilter::kSpeed);
    251   Verify(dex_location, CompilerFilter::kEverything);
    252 }
    253 
    254 // Case: We have a stripped (or resource-only) DEX file, no ODEX file and no
    255 // OAT file. Expect: The status is kNoDexOptNeeded.
    256 TEST_F(DexoptAnalyzerTest, ResourceOnlyDex) {
    257   std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
    258 
    259   Copy(GetStrippedDexSrc1(), dex_location);
    260 
    261   Verify(dex_location, CompilerFilter::kSpeed);
    262   Verify(dex_location, CompilerFilter::kExtract);
    263   Verify(dex_location, CompilerFilter::kQuicken);
    264 }
    265 
    266 // Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
    267 // OAT files both have patch delta of 0.
    268 TEST_F(DexoptAnalyzerTest, OdexOatOverlap) {
    269   std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
    270   std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
    271   std::string oat_location = GetOdexDir() + "/OdexOatOverlap.oat";
    272 
    273   Copy(GetDexSrc1(), dex_location);
    274   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
    275 
    276   // Create the oat file by copying the odex so they are located in the same
    277   // place in memory.
    278   Copy(odex_location, oat_location);
    279 
    280   Verify(dex_location, CompilerFilter::kSpeed);
    281 }
    282 
    283 // Case: We have a DEX file and a PIC ODEX file, but no OAT file.
    284 TEST_F(DexoptAnalyzerTest, DexPicOdexNoOat) {
    285   std::string dex_location = GetScratchDir() + "/DexPicOdexNoOat.jar";
    286   std::string odex_location = GetOdexDir() + "/DexPicOdexNoOat.odex";
    287 
    288   Copy(GetDexSrc1(), dex_location);
    289   GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
    290 
    291   Verify(dex_location, CompilerFilter::kSpeed);
    292   Verify(dex_location, CompilerFilter::kEverything);
    293 }
    294 
    295 // Case: We have a DEX file and a VerifyAtRuntime ODEX file, but no OAT file..
    296 TEST_F(DexoptAnalyzerTest, DexVerifyAtRuntimeOdexNoOat) {
    297   std::string dex_location = GetScratchDir() + "/DexVerifyAtRuntimeOdexNoOat.jar";
    298   std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex";
    299 
    300   Copy(GetDexSrc1(), dex_location);
    301   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
    302 
    303   Verify(dex_location, CompilerFilter::kExtract);
    304   Verify(dex_location, CompilerFilter::kSpeed);
    305 }
    306 
    307 // Case: Non-standard extension for dex file.
    308 TEST_F(DexoptAnalyzerTest, LongDexExtension) {
    309   std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
    310   Copy(GetDexSrc1(), dex_location);
    311 
    312   Verify(dex_location, CompilerFilter::kSpeed);
    313 }
    314 
    315 // Case: Very short, non-existent Dex location.
    316 TEST_F(DexoptAnalyzerTest, ShortDexLocation) {
    317   std::string dex_location = "/xx";
    318 
    319   Verify(dex_location, CompilerFilter::kSpeed);
    320 }
    321 
    322 }  // namespace art
    323