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 int dexoptanalyzerResult = Analyze(dex_file, compiler_filter, assume_profile_changed); 76 dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult); 77 OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable*/ false); 78 int assistantResult = oat_file_assistant.GetDexOptNeeded( 79 compiler_filter, assume_profile_changed); 80 EXPECT_EQ(assistantResult, dexoptanalyzerResult); 81 } 82 }; 83 84 // The tests below exercise the same test case from oat_file_assistant_test.cc. 85 86 // Case: We have a DEX file, but no OAT file for it. 87 TEST_F(DexoptAnalyzerTest, DexNoOat) { 88 std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; 89 Copy(GetDexSrc1(), dex_location); 90 91 Verify(dex_location, CompilerFilter::kSpeed); 92 Verify(dex_location, CompilerFilter::kExtract); 93 Verify(dex_location, CompilerFilter::kQuicken); 94 Verify(dex_location, CompilerFilter::kSpeedProfile); 95 } 96 97 // Case: We have a DEX file and up-to-date OAT file for it. 98 TEST_F(DexoptAnalyzerTest, OatUpToDate) { 99 std::string dex_location = GetScratchDir() + "/OatUpToDate.jar"; 100 Copy(GetDexSrc1(), dex_location); 101 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 102 103 Verify(dex_location, CompilerFilter::kSpeed); 104 Verify(dex_location, CompilerFilter::kQuicken); 105 Verify(dex_location, CompilerFilter::kExtract); 106 Verify(dex_location, CompilerFilter::kEverything); 107 } 108 109 // Case: We have a DEX file and speed-profile OAT file for it. 110 TEST_F(DexoptAnalyzerTest, ProfileOatUpToDate) { 111 std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar"; 112 Copy(GetDexSrc1(), dex_location); 113 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile); 114 115 Verify(dex_location, CompilerFilter::kSpeedProfile, false); 116 Verify(dex_location, CompilerFilter::kQuicken, false); 117 Verify(dex_location, CompilerFilter::kSpeedProfile, true); 118 Verify(dex_location, CompilerFilter::kQuicken, true); 119 } 120 121 // Case: We have a MultiDEX file and up-to-date OAT file for it. 122 TEST_F(DexoptAnalyzerTest, MultiDexOatUpToDate) { 123 std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar"; 124 Copy(GetMultiDexSrc1(), dex_location); 125 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 126 127 Verify(dex_location, CompilerFilter::kSpeed, false); 128 } 129 130 // Case: We have a MultiDEX file where the secondary dex file is out of date. 131 TEST_F(DexoptAnalyzerTest, MultiDexSecondaryOutOfDate) { 132 std::string dex_location = GetScratchDir() + "/MultiDexSecondaryOutOfDate.jar"; 133 134 // Compile code for GetMultiDexSrc1. 135 Copy(GetMultiDexSrc1(), dex_location); 136 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 137 138 // Now overwrite the dex file with GetMultiDexSrc2 so the secondary checksum 139 // is out of date. 140 Copy(GetMultiDexSrc2(), dex_location); 141 142 Verify(dex_location, CompilerFilter::kSpeed, false); 143 } 144 145 146 // Case: We have a DEX file and an OAT file out of date with respect to the 147 // dex checksum. 148 TEST_F(DexoptAnalyzerTest, OatDexOutOfDate) { 149 std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar"; 150 151 // We create a dex, generate an oat for it, then overwrite the dex with a 152 // different dex to make the oat out of date. 153 Copy(GetDexSrc1(), dex_location); 154 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 155 Copy(GetDexSrc2(), dex_location); 156 157 Verify(dex_location, CompilerFilter::kExtract); 158 Verify(dex_location, CompilerFilter::kSpeed); 159 } 160 161 // Case: We have a DEX file and an OAT file out of date with respect to the 162 // boot image. 163 TEST_F(DexoptAnalyzerTest, OatImageOutOfDate) { 164 std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar"; 165 166 Copy(GetDexSrc1(), dex_location); 167 GenerateOatForTest(dex_location.c_str(), 168 CompilerFilter::kSpeed, 169 /*relocate*/true, 170 /*pic*/false, 171 /*with_alternate_image*/true); 172 173 Verify(dex_location, CompilerFilter::kExtract); 174 Verify(dex_location, CompilerFilter::kQuicken); 175 Verify(dex_location, CompilerFilter::kSpeed); 176 } 177 178 // Case: We have a DEX file and a verify-at-runtime OAT file out of date with 179 // respect to the boot image. 180 // It shouldn't matter that the OAT file is out of date, because it is 181 // verify-at-runtime. 182 TEST_F(DexoptAnalyzerTest, OatVerifyAtRuntimeImageOutOfDate) { 183 std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar"; 184 185 Copy(GetDexSrc1(), dex_location); 186 GenerateOatForTest(dex_location.c_str(), 187 CompilerFilter::kExtract, 188 /*relocate*/true, 189 /*pic*/false, 190 /*with_alternate_image*/true); 191 192 Verify(dex_location, CompilerFilter::kExtract); 193 Verify(dex_location, CompilerFilter::kQuicken); 194 } 195 196 // Case: We have a DEX file and an ODEX file, but no OAT file. 197 TEST_F(DexoptAnalyzerTest, DexOdexNoOat) { 198 std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar"; 199 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; 200 201 Copy(GetDexSrc1(), dex_location); 202 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 203 204 Verify(dex_location, CompilerFilter::kExtract); 205 Verify(dex_location, CompilerFilter::kSpeed); 206 } 207 208 // Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file. 209 TEST_F(DexoptAnalyzerTest, StrippedDexOdexNoOat) { 210 std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar"; 211 std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex"; 212 213 Copy(GetDexSrc1(), dex_location); 214 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 215 216 // Strip the dex file 217 Copy(GetStrippedDexSrc1(), dex_location); 218 219 Verify(dex_location, CompilerFilter::kSpeed); 220 } 221 222 // Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file. 223 TEST_F(DexoptAnalyzerTest, StrippedDexOdexOat) { 224 std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar"; 225 std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex"; 226 227 // Create the oat file from a different dex file so it looks out of date. 228 Copy(GetDexSrc2(), dex_location); 229 GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); 230 231 // Create the odex file 232 Copy(GetDexSrc1(), dex_location); 233 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 234 235 // Strip the dex file. 236 Copy(GetStrippedDexSrc1(), dex_location); 237 238 Verify(dex_location, CompilerFilter::kExtract); 239 Verify(dex_location, CompilerFilter::kSpeed); 240 Verify(dex_location, CompilerFilter::kEverything); 241 } 242 243 // Case: We have a stripped (or resource-only) DEX file, no ODEX file and no 244 // OAT file. Expect: The status is kNoDexOptNeeded. 245 TEST_F(DexoptAnalyzerTest, ResourceOnlyDex) { 246 std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar"; 247 248 Copy(GetStrippedDexSrc1(), dex_location); 249 250 Verify(dex_location, CompilerFilter::kSpeed); 251 Verify(dex_location, CompilerFilter::kExtract); 252 Verify(dex_location, CompilerFilter::kQuicken); 253 } 254 255 // Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and 256 // OAT files both have patch delta of 0. 257 TEST_F(DexoptAnalyzerTest, OdexOatOverlap) { 258 std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar"; 259 std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex"; 260 std::string oat_location = GetOdexDir() + "/OdexOatOverlap.oat"; 261 262 Copy(GetDexSrc1(), dex_location); 263 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 264 265 // Create the oat file by copying the odex so they are located in the same 266 // place in memory. 267 Copy(odex_location, oat_location); 268 269 Verify(dex_location, CompilerFilter::kSpeed); 270 } 271 272 // Case: We have a DEX file and a PIC ODEX file, but no OAT file. 273 TEST_F(DexoptAnalyzerTest, DexPicOdexNoOat) { 274 std::string dex_location = GetScratchDir() + "/DexPicOdexNoOat.jar"; 275 std::string odex_location = GetOdexDir() + "/DexPicOdexNoOat.odex"; 276 277 Copy(GetDexSrc1(), dex_location); 278 GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed); 279 280 Verify(dex_location, CompilerFilter::kSpeed); 281 Verify(dex_location, CompilerFilter::kEverything); 282 } 283 284 // Case: We have a DEX file and a VerifyAtRuntime ODEX file, but no OAT file.. 285 TEST_F(DexoptAnalyzerTest, DexVerifyAtRuntimeOdexNoOat) { 286 std::string dex_location = GetScratchDir() + "/DexVerifyAtRuntimeOdexNoOat.jar"; 287 std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex"; 288 289 Copy(GetDexSrc1(), dex_location); 290 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract); 291 292 Verify(dex_location, CompilerFilter::kExtract); 293 Verify(dex_location, CompilerFilter::kSpeed); 294 } 295 296 // Case: Non-standard extension for dex file. 297 TEST_F(DexoptAnalyzerTest, LongDexExtension) { 298 std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx"; 299 Copy(GetDexSrc1(), dex_location); 300 301 Verify(dex_location, CompilerFilter::kSpeed); 302 } 303 304 // Case: Very short, non-existent Dex location. 305 TEST_F(DexoptAnalyzerTest, ShortDexLocation) { 306 std::string dex_location = "/xx"; 307 308 Verify(dex_location, CompilerFilter::kSpeed); 309 } 310 311 } // namespace art 312