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