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:
GetDexoptAnalyzerCmd()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
Analyze(const std::string & dex_file,CompilerFilter::Filter compiler_filter,bool assume_profile_changed)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
DexoptanalyzerToOatFileAssistant(int dexoptanalyzerResult)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.
Verify(const std::string & dex_file,CompilerFilter::Filter compiler_filter,bool assume_profile_changed=false)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.
TEST_F(DexoptAnalyzerTest,DexNoOat)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.
TEST_F(DexoptAnalyzerTest,OatUpToDate)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.
TEST_F(DexoptAnalyzerTest,ProfileOatUpToDate)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.
TEST_F(DexoptAnalyzerTest,MultiDexOatUpToDate)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.
TEST_F(DexoptAnalyzerTest,MultiDexSecondaryOutOfDate)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.
TEST_F(DexoptAnalyzerTest,OatDexOutOfDate)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.
TEST_F(DexoptAnalyzerTest,OatImageOutOfDate)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.
TEST_F(DexoptAnalyzerTest,OatVerifyAtRuntimeImageOutOfDate)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.
TEST_F(DexoptAnalyzerTest,DexOdexNoOat)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.
TEST_F(DexoptAnalyzerTest,StrippedDexOdexNoOat)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.
TEST_F(DexoptAnalyzerTest,StrippedDexOdexOat)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.
TEST_F(DexoptAnalyzerTest,ResourceOnlyDex)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.
TEST_F(DexoptAnalyzerTest,OdexOatOverlap)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.
TEST_F(DexoptAnalyzerTest,DexPicOdexNoOat)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..
TEST_F(DexoptAnalyzerTest,DexVerifyAtRuntimeOdexNoOat)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.
TEST_F(DexoptAnalyzerTest,LongDexExtension)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.
TEST_F(DexoptAnalyzerTest,ShortDexLocation)305 TEST_F(DexoptAnalyzerTest, ShortDexLocation) {
306 std::string dex_location = "/xx";
307
308 Verify(dex_location, CompilerFilter::kSpeed);
309 }
310
311 } // namespace art
312