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 <sys/wait.h>
18 #include <unistd.h>
19
20 #include <algorithm>
21 #include <iterator>
22 #include <optional>
23 #include <regex>
24 #include <sstream>
25 #include <string>
26 #include <vector>
27
28 #include "android-base/logging.h"
29 #include "android-base/macros.h"
30 #include "android-base/stringprintf.h"
31 #include "arch/instruction_set_features.h"
32 #include "base/macros.h"
33 #include "base/mutex-inl.h"
34 #include "base/utils.h"
35 #include "base/zip_archive.h"
36 #include "common_runtime_test.h"
37 #include "dex/art_dex_file_loader.h"
38 #include "dex/base64_test_util.h"
39 #include "dex/bytecode_utils.h"
40 #include "dex/class_accessor-inl.h"
41 #include "dex/code_item_accessors-inl.h"
42 #include "dex/dex_file-inl.h"
43 #include "dex/dex_file_loader.h"
44 #include "dex2oat_environment_test.h"
45 #include "gc_root-inl.h"
46 #include "intern_table-inl.h"
47 #include "oat/elf_file.h"
48 #include "oat/elf_file_impl.h"
49 #include "oat/oat.h"
50 #include "oat/oat_file.h"
51 #include "profile/profile_compilation_info.h"
52 #include "vdex_file.h"
53 #include "ziparchive/zip_writer.h"
54
55 namespace art {
56
57 using android::base::StringPrintf;
58
59 class Dex2oatTest : public Dex2oatEnvironmentTest {
60 public:
TearDown()61 void TearDown() override {
62 Dex2oatEnvironmentTest::TearDown();
63
64 output_ = "";
65 error_msg_ = "";
66 }
67
68 protected:
GenerateOdexForTestWithStatus(const std::vector<std::string> & dex_locations,const std::string & odex_location,CompilerFilter::Filter filter,std::string * error_msg,const std::vector<std::string> & extra_args={},bool use_fd=false)69 int GenerateOdexForTestWithStatus(const std::vector<std::string>& dex_locations,
70 const std::string& odex_location,
71 CompilerFilter::Filter filter,
72 std::string* error_msg,
73 const std::vector<std::string>& extra_args = {},
74 bool use_fd = false) {
75 std::unique_ptr<File> oat_file;
76 std::vector<std::string> args;
77 args.reserve(dex_locations.size() + extra_args.size() + 6);
78 // Add dex file args.
79 for (const std::string& dex_location : dex_locations) {
80 args.push_back("--dex-file=" + dex_location);
81 }
82 if (use_fd) {
83 oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
84 CHECK(oat_file != nullptr) << odex_location;
85 args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
86 args.push_back("--oat-location=" + odex_location);
87 } else {
88 args.push_back("--oat-file=" + odex_location);
89 }
90 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
91 args.push_back("--runtime-arg");
92 args.push_back("-Xnorelocate");
93
94 // Unless otherwise stated, use a small amount of threads, so that potential aborts are
95 // shorter. This can be overridden with extra_args.
96 args.push_back("-j4");
97
98 args.insert(args.end(), extra_args.begin(), extra_args.end());
99
100 int status = Dex2Oat(args, &output_, error_msg);
101 if (oat_file != nullptr) {
102 CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
103 }
104 return status;
105 }
106
GenerateOdexForTest(const std::string & dex_location,const std::string & odex_location,CompilerFilter::Filter filter,const std::vector<std::string> & extra_args={},bool expect_success=true,bool use_fd=false,bool use_zip_fd=false)107 ::testing::AssertionResult GenerateOdexForTest(const std::string& dex_location,
108 const std::string& odex_location,
109 CompilerFilter::Filter filter,
110 const std::vector<std::string>& extra_args = {},
111 bool expect_success = true,
112 bool use_fd = false,
113 bool use_zip_fd = false) WARN_UNUSED {
114 return GenerateOdexForTest(dex_location,
115 odex_location,
116 filter,
117 extra_args,
118 expect_success,
119 use_fd,
120 use_zip_fd,
__anon390640650102(const OatFile&) 121 [](const OatFile&) {});
122 }
123
124 bool test_accepts_odex_file_on_failure = false;
125
126 template <typename T>
GenerateOdexForTest(const std::string & dex_location,const std::string & odex_location,CompilerFilter::Filter filter,const std::vector<std::string> & extra_args,bool expect_success,bool use_fd,bool use_zip_fd,T check_oat)127 ::testing::AssertionResult GenerateOdexForTest(const std::string& dex_location,
128 const std::string& odex_location,
129 CompilerFilter::Filter filter,
130 const std::vector<std::string>& extra_args,
131 bool expect_success,
132 bool use_fd,
133 bool use_zip_fd,
134 T check_oat) WARN_UNUSED {
135 std::vector<std::string> dex_locations;
136 if (use_zip_fd) {
137 std::string loc_arg = "--zip-location=" + dex_location;
138 CHECK(std::any_of(extra_args.begin(), extra_args.end(), [&](const std::string& s) {
139 return s == loc_arg;
140 }));
141 CHECK(std::any_of(extra_args.begin(), extra_args.end(), [](const std::string& s) {
142 return s.starts_with("--zip-fd=");
143 }));
144 } else {
145 dex_locations.push_back(dex_location);
146 }
147 std::string error_msg;
148 int status = GenerateOdexForTestWithStatus(
149 dex_locations, odex_location, filter, &error_msg, extra_args, use_fd);
150 bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
151 if (expect_success) {
152 if (!success) {
153 return ::testing::AssertionFailure() << "Failed to compile odex: " << error_msg << std::endl
154 << output_;
155 }
156
157 // Verify the odex file was generated as expected.
158 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
159 odex_location,
160 odex_location,
161 /*executable=*/false,
162 /*low_4gb=*/false,
163 dex_location,
164 &error_msg));
165 if (odex_file == nullptr) {
166 return ::testing::AssertionFailure() << "Could not open odex file: " << error_msg;
167 }
168
169 CheckFilter(filter, odex_file->GetCompilerFilter());
170 check_oat(*(odex_file.get()));
171 } else {
172 if (success) {
173 return ::testing::AssertionFailure() << "Succeeded to compile odex: " << output_;
174 }
175
176 error_msg_ = error_msg;
177
178 if (!test_accepts_odex_file_on_failure) {
179 // Verify there's no loadable odex file.
180 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
181 odex_location,
182 odex_location,
183 /*executable=*/false,
184 /*low_4gb=*/false,
185 dex_location,
186 &error_msg));
187 if (odex_file != nullptr) {
188 return ::testing::AssertionFailure() << "Could open odex file: " << error_msg;
189 }
190 }
191 }
192 return ::testing::AssertionSuccess();
193 }
194
195 // Check the input compiler filter against the generated oat file's filter. May be overridden
196 // in subclasses when equality is not expected.
CheckFilter(CompilerFilter::Filter expected,CompilerFilter::Filter actual)197 virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
198 EXPECT_EQ(expected, actual);
199 }
200
201 std::string output_ = "";
202 std::string error_msg_ = "";
203 };
204
205 // This test class provides an easy way to validate an expected filter which is different
206 // then the one pass to generate the odex file (compared to adding yet another argument
207 // to what's already huge test methods).
208 class Dex2oatWithExpectedFilterTest : public Dex2oatTest {
209 protected:
CheckFilter(CompilerFilter::Filter expected,CompilerFilter::Filter actual)210 void CheckFilter([[maybe_unused]] CompilerFilter::Filter expected,
211 CompilerFilter::Filter actual) override {
212 EXPECT_EQ(expected_filter_, actual);
213 }
214
215 CompilerFilter::Filter expected_filter_;
216 };
217
218 class Dex2oatSwapTest : public Dex2oatTest {
219 protected:
RunTest(bool use_fd,bool expect_use,const std::vector<std::string> & extra_args={})220 void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
221 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
222 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
223
224 Copy(GetTestDexFileName(), dex_location);
225
226 std::vector<std::string> copy(extra_args);
227
228 std::unique_ptr<ScratchFile> sf;
229 if (use_fd) {
230 sf.reset(new ScratchFile());
231 copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
232 } else {
233 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
234 copy.push_back("--swap-file=" + swap_location);
235 }
236 ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy));
237
238 CheckValidity();
239 CheckResult(expect_use);
240 }
241
GetTestDexFileName()242 virtual std::string GetTestDexFileName() {
243 return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps");
244 }
245
CheckResult(bool expect_use)246 virtual void CheckResult(bool expect_use) {
247 if (kIsTargetBuild) {
248 CheckTargetResult(expect_use);
249 } else {
250 CheckHostResult(expect_use);
251 }
252 }
253
CheckTargetResult(bool expect_use)254 virtual void CheckTargetResult([[maybe_unused]] bool expect_use) {
255 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
256 // something for variants with file descriptor where we can control the lifetime of
257 // the swap file and thus take a look at it.
258 }
259
CheckHostResult(bool expect_use)260 virtual void CheckHostResult(bool expect_use) {
261 if (!kIsTargetBuild) {
262 if (expect_use) {
263 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
264 << output_;
265 } else {
266 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
267 << output_;
268 }
269 }
270 }
271
272 // Check whether the dex2oat run was really successful.
CheckValidity()273 virtual void CheckValidity() {
274 if (kIsTargetBuild) {
275 CheckTargetValidity();
276 } else {
277 CheckHostValidity();
278 }
279 }
280
CheckTargetValidity()281 virtual void CheckTargetValidity() {
282 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
283 // something for variants with file descriptor where we can control the lifetime of
284 // the swap file and thus take a look at it.
285 }
286
287 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()288 virtual void CheckHostValidity() {
289 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
290 }
291 };
292
TEST_F(Dex2oatSwapTest,DoNotUseSwapDefaultSingleSmall)293 TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
294 RunTest(/*use_fd=*/false, /*expect_use=*/false);
295 RunTest(/*use_fd=*/true, /*expect_use=*/false);
296 }
297
TEST_F(Dex2oatSwapTest,DoNotUseSwapSingle)298 TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
299 RunTest(/*use_fd=*/false, /*expect_use=*/false, {"--swap-dex-size-threshold=0"});
300 RunTest(/*use_fd=*/true, /*expect_use=*/false, {"--swap-dex-size-threshold=0"});
301 }
302
TEST_F(Dex2oatSwapTest,DoNotUseSwapSmall)303 TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
304 RunTest(/*use_fd=*/false, /*expect_use=*/false, {"--swap-dex-count-threshold=0"});
305 RunTest(/*use_fd=*/true, /*expect_use=*/false, {"--swap-dex-count-threshold=0"});
306 }
307
TEST_F(Dex2oatSwapTest,DoUseSwapSingleSmall)308 TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
309 RunTest(/*use_fd=*/false,
310 /*expect_use=*/true,
311 {"--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0"});
312 RunTest(/*use_fd=*/true,
313 /*expect_use=*/true,
314 {"--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0"});
315 }
316
317 class Dex2oatSwapUseTest : public Dex2oatSwapTest {
318 protected:
CheckHostResult(bool expect_use)319 void CheckHostResult(bool expect_use) override {
320 if (!kIsTargetBuild) {
321 if (expect_use) {
322 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
323 << output_;
324 } else {
325 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
326 << output_;
327 }
328 }
329 }
330
GetTestDexFileName()331 std::string GetTestDexFileName() override {
332 // Use Statics as it has a handful of functions.
333 return CommonRuntimeTest::GetTestDexFileName("Statics");
334 }
335
GrabResult1()336 void GrabResult1() {
337 if (!kIsTargetBuild) {
338 native_alloc_1_ = ParseNativeAlloc();
339 swap_1_ = ParseSwap(/*expected=*/false);
340 } else {
341 native_alloc_1_ = std::numeric_limits<size_t>::max();
342 swap_1_ = 0;
343 }
344 }
345
GrabResult2()346 void GrabResult2() {
347 if (!kIsTargetBuild) {
348 native_alloc_2_ = ParseNativeAlloc();
349 swap_2_ = ParseSwap(/*expected=*/true);
350 } else {
351 native_alloc_2_ = 0;
352 swap_2_ = std::numeric_limits<size_t>::max();
353 }
354 }
355
356 private:
ParseNativeAlloc()357 size_t ParseNativeAlloc() {
358 std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)");
359 std::smatch native_alloc_match;
360 bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex);
361 if (!found) {
362 EXPECT_TRUE(found);
363 return 0;
364 }
365 if (native_alloc_match.size() != 2U) {
366 EXPECT_EQ(native_alloc_match.size(), 2U);
367 return 0;
368 }
369
370 std::istringstream stream(native_alloc_match[1].str());
371 size_t value;
372 stream >> value;
373
374 return value;
375 }
376
ParseSwap(bool expected)377 size_t ParseSwap(bool expected) {
378 std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)");
379 std::smatch swap_match;
380 bool found = std::regex_search(output_, swap_match, swap_regex);
381 if (found != expected) {
382 EXPECT_EQ(expected, found);
383 return 0;
384 }
385
386 if (!found) {
387 return 0;
388 }
389
390 if (swap_match.size() != 2U) {
391 EXPECT_EQ(swap_match.size(), 2U);
392 return 0;
393 }
394
395 std::istringstream stream(swap_match[1].str());
396 size_t value;
397 stream >> value;
398
399 return value;
400 }
401
402 protected:
403 size_t native_alloc_1_;
404 size_t native_alloc_2_;
405
406 size_t swap_1_;
407 size_t swap_2_;
408 };
409
TEST_F(Dex2oatSwapUseTest,CheckSwapUsage)410 TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
411 // Native memory usage isn't correctly tracked when running under ASan.
412 TEST_DISABLED_FOR_MEMORY_TOOL();
413
414 // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
415 // hold true on some x86 or x86_64 systems; disable this test while we
416 // investigate (b/29259363).
417 TEST_DISABLED_FOR_X86();
418 TEST_DISABLED_FOR_X86_64();
419
420 RunTest(/*use_fd=*/false,
421 /*expect_use=*/false);
422 GrabResult1();
423 std::string output_1 = output_;
424
425 output_ = "";
426
427 RunTest(/*use_fd=*/false,
428 /*expect_use=*/true,
429 {"--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0"});
430 GrabResult2();
431 std::string output_2 = output_;
432
433 if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) {
434 EXPECT_LT(native_alloc_2_, native_alloc_1_);
435 EXPECT_LT(swap_1_, swap_2_);
436
437 LOG(ERROR) << output_1;
438 LOG(ERROR) << output_2;
439 }
440 }
441
442 class Dex2oatVeryLargeTest : public Dex2oatTest {
443 protected:
CheckFilter(CompilerFilter::Filter input,CompilerFilter::Filter result)444 void CheckFilter([[maybe_unused]] CompilerFilter::Filter input,
445 [[maybe_unused]] CompilerFilter::Filter result) override {
446 // Ignore, we'll do our own checks.
447 }
448
RunTest(CompilerFilter::Filter filter,bool expect_large,bool expect_downgrade,const std::vector<std::string> & extra_args={})449 void RunTest(CompilerFilter::Filter filter,
450 bool expect_large,
451 bool expect_downgrade,
452 const std::vector<std::string>& extra_args = {}) {
453 RunTest(filter, filter, expect_large, expect_downgrade, extra_args);
454 }
455
RunTest(CompilerFilter::Filter filter,CompilerFilter::Filter expected_filter,bool expect_large,bool expect_downgrade,const std::vector<std::string> & extra_args={})456 void RunTest(CompilerFilter::Filter filter,
457 CompilerFilter::Filter expected_filter,
458 bool expect_large,
459 bool expect_downgrade,
460 const std::vector<std::string>& extra_args = {}) {
461 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
462 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
463 std::string app_image_file = GetScratchDir() + "/Test.art";
464
465 Copy(GetDexSrc1(), dex_location);
466
467 std::vector<std::string> new_args(extra_args);
468 new_args.push_back("--app-image-file=" + app_image_file);
469 ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, filter, new_args));
470
471 CheckValidity();
472 CheckResult(dex_location,
473 odex_location,
474 app_image_file,
475 expected_filter,
476 expect_large,
477 expect_downgrade);
478 }
479
CheckResult(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file,CompilerFilter::Filter expected_filter,bool expect_large,bool expect_downgrade)480 void CheckResult(const std::string& dex_location,
481 const std::string& odex_location,
482 const std::string& app_image_file,
483 CompilerFilter::Filter expected_filter,
484 bool expect_large,
485 bool expect_downgrade) {
486 if (expect_downgrade) {
487 EXPECT_TRUE(expect_large);
488 }
489 // Host/target independent checks.
490 std::string error_msg;
491 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
492 odex_location,
493 odex_location,
494 /*executable=*/false,
495 /*low_4gb=*/false,
496 dex_location,
497 &error_msg));
498 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
499 EXPECT_GT(app_image_file.length(), 0u);
500 std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file.c_str()));
501 if (expect_large) {
502 // Note: we cannot check the following
503 // EXPECT_FALSE(CompilerFilter::IsAotCompilationEnabled(odex_file->GetCompilerFilter()));
504 // The reason is that the filter override currently happens when the dex files are
505 // loaded in dex2oat, which is after the oat file has been started. Thus, the header
506 // store cannot be changed, and the original filter is set in stone.
507
508 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
509 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
510 ASSERT_TRUE(dex_file != nullptr);
511 uint32_t class_def_count = dex_file->NumClassDefs();
512 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
513 for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
514 OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
515 EXPECT_EQ(oat_class.GetType(), OatClassType::kNoneCompiled);
516 }
517 }
518
519 // If the input filter was "below," it should have been used.
520 EXPECT_EQ(odex_file->GetCompilerFilter(), expected_filter);
521
522 // If expect large, make sure the app image isn't generated or is empty.
523 if (file != nullptr) {
524 EXPECT_EQ(file->GetLength(), 0u);
525 }
526 } else {
527 EXPECT_EQ(odex_file->GetCompilerFilter(), expected_filter);
528 ASSERT_TRUE(file != nullptr) << app_image_file;
529 EXPECT_GT(file->GetLength(), 0u);
530 }
531
532 // Host/target dependent checks.
533 if (kIsTargetBuild) {
534 CheckTargetResult(expect_downgrade);
535 } else {
536 CheckHostResult(expect_downgrade);
537 }
538 }
539
CheckTargetResult(bool expect_downgrade)540 void CheckTargetResult([[maybe_unused]] bool expect_downgrade) {
541 // TODO: Ignore for now. May do something for fd things.
542 }
543
CheckHostResult(bool expect_downgrade)544 void CheckHostResult(bool expect_downgrade) {
545 if (!kIsTargetBuild) {
546 if (expect_downgrade) {
547 EXPECT_NE(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
548 } else {
549 EXPECT_EQ(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
550 }
551 }
552 }
553
554 // Check whether the dex2oat run was really successful.
CheckValidity()555 void CheckValidity() {
556 if (kIsTargetBuild) {
557 CheckTargetValidity();
558 } else {
559 CheckHostValidity();
560 }
561 }
562
CheckTargetValidity()563 void CheckTargetValidity() {
564 // TODO: Ignore for now.
565 }
566
567 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()568 void CheckHostValidity() {
569 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
570 }
571 };
572
TEST_F(Dex2oatVeryLargeTest,DontUseVeryLarge)573 TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
574 RunTest(CompilerFilter::kAssumeVerified, false, false);
575 RunTest(CompilerFilter::kSpeed, false, false);
576
577 RunTest(CompilerFilter::kAssumeVerified, false, false, {"--very-large-app-threshold=10000000"});
578 RunTest(CompilerFilter::kSpeed, false, false, {"--very-large-app-threshold=10000000"});
579 }
580
TEST_F(Dex2oatVeryLargeTest,UseVeryLarge)581 TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
582 RunTest(CompilerFilter::kAssumeVerified, true, false, {"--very-large-app-threshold=100"});
583 RunTest(CompilerFilter::kSpeed, true, true, {"--very-large-app-threshold=100"});
584 }
585
586 // Regressin test for b/35665292.
TEST_F(Dex2oatVeryLargeTest,SpeedProfileNoProfile)587 TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) {
588 // Test that dex2oat doesn't crash with speed-profile but no input profile.
589 RunTest(CompilerFilter::kSpeedProfile, CompilerFilter::kVerify, false, false);
590 }
591
592 class Dex2oatLayoutTest : public Dex2oatTest {
593 protected:
CheckFilter(CompilerFilter::Filter input,CompilerFilter::Filter result)594 void CheckFilter([[maybe_unused]] CompilerFilter::Filter input,
595 [[maybe_unused]] CompilerFilter::Filter result) override {
596 // Ignore, we'll do our own checks.
597 }
598
599 // Emits a profile with a single dex file with the given location and classes ranging
600 // from `class_offset` to `class_offset + num_classes`.
GenerateProfile(const std::string & test_profile,const std::string & dex_location,size_t num_classes,size_t class_offset=0)601 void GenerateProfile(const std::string& test_profile,
602 const std::string& dex_location,
603 size_t num_classes,
604 size_t class_offset = 0) {
605 const char* location = dex_location.c_str();
606 std::string error_msg;
607 std::vector<std::unique_ptr<const DexFile>> dex_files;
608 ArtDexFileLoader dex_file_loader(location);
609 ASSERT_TRUE(dex_file_loader.Open(
610 /*verify=*/true, /*verify_checksum=*/true, &error_msg, &dex_files));
611 EXPECT_EQ(dex_files.size(), 1U);
612 std::unique_ptr<const DexFile>& dex_file = dex_files[0];
613
614 int profile_test_fd =
615 open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
616 CHECK_GE(profile_test_fd, 0);
617
618 ProfileCompilationInfo info;
619 std::vector<dex::TypeIndex> classes;
620 for (size_t i = 0; i < num_classes; ++i) {
621 classes.push_back(dex::TypeIndex(class_offset + 1 + i));
622 }
623 info.AddClassesForDex(dex_file.get(), classes.begin(), classes.end());
624 bool result = info.Save(profile_test_fd);
625 close(profile_test_fd);
626 ASSERT_TRUE(result);
627 }
628
629 // Compiles a dex file with profiles.
CompileProfileOdex(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file_name,bool use_fd,const std::vector<std::string> & profile_locations,const std::vector<std::string> & extra_args={},bool expect_success=true)630 void CompileProfileOdex(const std::string& dex_location,
631 const std::string& odex_location,
632 const std::string& app_image_file_name,
633 bool use_fd,
634 const std::vector<std::string>& profile_locations,
635 const std::vector<std::string>& extra_args = {},
636 bool expect_success = true) {
637 std::vector<std::string> copy(extra_args);
638 for (const std::string& profile_location : profile_locations) {
639 copy.push_back("--profile-file=" + profile_location);
640 }
641 std::unique_ptr<File> app_image_file;
642 if (!app_image_file_name.empty()) {
643 if (use_fd) {
644 app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str()));
645 copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd()));
646 } else {
647 copy.push_back("--app-image-file=" + app_image_file_name);
648 }
649 }
650 ASSERT_TRUE(GenerateOdexForTest(
651 dex_location, odex_location, CompilerFilter::kSpeedProfile, copy, expect_success, use_fd));
652 if (app_image_file != nullptr) {
653 ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
654 }
655 }
656
657 // Same as above, but generates the profile internally with classes ranging from 0 to
658 // `num_profile_classes`.
CompileProfileOdex(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file_name,bool use_fd,size_t num_profile_classes,const std::vector<std::string> & extra_args={},bool expect_success=true)659 void CompileProfileOdex(const std::string& dex_location,
660 const std::string& odex_location,
661 const std::string& app_image_file_name,
662 bool use_fd,
663 size_t num_profile_classes,
664 const std::vector<std::string>& extra_args = {},
665 bool expect_success = true) {
666 const std::string profile_location = GetScratchDir() + "/primary.prof";
667 GenerateProfile(profile_location, dex_location, num_profile_classes);
668 CompileProfileOdex(dex_location,
669 odex_location,
670 app_image_file_name,
671 use_fd,
672 {profile_location},
673 extra_args,
674 expect_success);
675 }
676
GetImageObjectSectionSize(const std::string & image_file_name)677 uint32_t GetImageObjectSectionSize(const std::string& image_file_name) {
678 EXPECT_FALSE(image_file_name.empty());
679 std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
680 CHECK(file != nullptr);
681 ImageHeader image_header;
682 const bool success = file->ReadFully(&image_header, sizeof(image_header));
683 CHECK(success);
684 CHECK(image_header.IsValid());
685 ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
686 return image_header.GetObjectsSection().Size();
687 }
688
RunTest(bool app_image)689 void RunTest(bool app_image) {
690 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
691 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
692 std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art") : "";
693 Copy(GetDexSrc2(), dex_location);
694
695 uint32_t image_file_empty_profile = 0;
696 if (app_image) {
697 CompileProfileOdex(dex_location,
698 odex_location,
699 app_image_file,
700 /*use_fd=*/false,
701 /*num_profile_classes=*/0);
702 CheckValidity();
703 // Don't check the result since CheckResult relies on the class being in the profile.
704 image_file_empty_profile = GetImageObjectSectionSize(app_image_file);
705 EXPECT_GT(image_file_empty_profile, 0u);
706 CheckCompilerFilter(dex_location, odex_location, CompilerFilter::Filter::kVerify);
707 }
708
709 // Small profile.
710 CompileProfileOdex(dex_location,
711 odex_location,
712 app_image_file,
713 /*use_fd=*/false,
714 /*num_profile_classes=*/1);
715 CheckValidity();
716 CheckResult(dex_location, odex_location, app_image_file);
717 CheckCompilerFilter(dex_location, odex_location, CompilerFilter::Filter::kSpeedProfile);
718
719 if (app_image) {
720 // Test that the profile made a difference by adding more classes.
721 const uint32_t image_file_small_profile = GetImageObjectSectionSize(app_image_file);
722 ASSERT_LT(image_file_empty_profile, image_file_small_profile);
723 }
724 }
725
CheckCompilerFilter(const std::string & dex_location,const std::string & odex_location,CompilerFilter::Filter expected_filter)726 void CheckCompilerFilter(const std::string& dex_location,
727 const std::string& odex_location,
728 CompilerFilter::Filter expected_filter) {
729 std::string error_msg;
730 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
731 odex_location,
732 odex_location,
733 /*executable=*/false,
734 /*low_4gb=*/false,
735 dex_location,
736 &error_msg));
737 EXPECT_EQ(odex_file->GetCompilerFilter(), expected_filter);
738 }
739
RunTestVDex()740 void RunTestVDex() {
741 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
742 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
743 std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
744 std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art";
745 Copy(GetDexSrc2(), dex_location);
746
747 std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
748 CHECK(vdex_file1 != nullptr) << vdex_location;
749 ScratchFile vdex_file2;
750 {
751 std::string input_vdex = "--input-vdex-fd=-1";
752 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
753 CompileProfileOdex(dex_location,
754 odex_location,
755 app_image_file_name,
756 /*use_fd=*/true,
757 /*num_profile_classes=*/1,
758 {input_vdex, output_vdex});
759 EXPECT_GT(vdex_file1->GetLength(), 0u);
760 }
761 {
762 // Test that vdex and dexlayout fail gracefully.
763 std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
764 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
765 CompileProfileOdex(dex_location,
766 odex_location,
767 app_image_file_name,
768 /*use_fd=*/true,
769 /*num_profile_classes=*/1,
770 {input_vdex, output_vdex},
771 /*expect_success=*/true);
772 EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
773 }
774 ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
775 CheckValidity();
776 }
777
CheckResult(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file_name)778 void CheckResult(const std::string& dex_location,
779 const std::string& odex_location,
780 const std::string& app_image_file_name) {
781 // Host/target independent checks.
782 std::string error_msg;
783 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
784 odex_location,
785 odex_location,
786 /*executable=*/false,
787 /*low_4gb=*/false,
788 dex_location,
789 &error_msg));
790 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
791
792 const char* location = dex_location.c_str();
793 std::vector<std::unique_ptr<const DexFile>> dex_files;
794 ArtDexFileLoader dex_file_loader(location);
795 ASSERT_TRUE(dex_file_loader.Open(
796 /*verify=*/true, /*verify_checksum=*/true, &error_msg, &dex_files));
797 EXPECT_EQ(dex_files.size(), 1U);
798 std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
799
800 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
801 std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
802 ASSERT_TRUE(new_dex_file != nullptr);
803 uint32_t class_def_count = new_dex_file->NumClassDefs();
804 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
805 ASSERT_GE(class_def_count, 2U);
806
807 // Make sure the indexes stay the same.
808 std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
809 std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
810 std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
811 std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
812 EXPECT_EQ(old_class0, new_class0);
813 EXPECT_EQ(old_class1, new_class1);
814 }
815
816 EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
817
818 if (!app_image_file_name.empty()) {
819 // Go peek at the image header to make sure it was large enough to contain the class.
820 std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str()));
821 ImageHeader image_header;
822 bool success = file->ReadFully(&image_header, sizeof(image_header));
823 ASSERT_TRUE(success);
824 ASSERT_TRUE(image_header.IsValid());
825 EXPECT_GT(image_header.GetObjectsSection().Size(), 0u);
826 }
827 }
828
829 // Check whether the dex2oat run was really successful.
CheckValidity()830 void CheckValidity() {
831 if (kIsTargetBuild) {
832 CheckTargetValidity();
833 } else {
834 CheckHostValidity();
835 }
836 }
837
CheckTargetValidity()838 void CheckTargetValidity() {
839 // TODO: Ignore for now.
840 }
841
842 // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()843 void CheckHostValidity() {
844 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
845 }
846 };
847
TEST_F(Dex2oatLayoutTest,TestLayout)848 TEST_F(Dex2oatLayoutTest, TestLayout) { RunTest(/*app_image=*/false); }
849
TEST_F(Dex2oatLayoutTest,TestLayoutAppImage)850 TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) { RunTest(/*app_image=*/true); }
851
TEST_F(Dex2oatLayoutTest,TestLayoutAppImageMissingBootImage)852 TEST_F(Dex2oatLayoutTest, TestLayoutAppImageMissingBootImage) {
853 std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
854 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
855 std::string app_image_file = GetOdexDir() + "/DexOdexNoOat.art";
856 Copy(GetDexSrc2(), dex_location);
857
858 CompileProfileOdex(dex_location,
859 odex_location,
860 app_image_file,
861 /*use_fd=*/false,
862 /*num_profile_classes=*/1,
863 /*extra_args=*/{"--boot-image=/nonx/boot.art"},
864 /*expect_success=*/true);
865
866 // Verify the odex file does not require an image.
867 std::string error_msg;
868 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
869 odex_location,
870 odex_location,
871 /*executable=*/false,
872 /*low_4gb=*/false,
873 dex_location,
874 &error_msg));
875 ASSERT_TRUE(odex_file != nullptr) << "Could not open odex file: " << error_msg;
876
877 CheckFilter(CompilerFilter::kSpeedProfile, odex_file->GetCompilerFilter());
878 ASSERT_FALSE(odex_file->GetOatHeader().RequiresImage());
879 }
880
TEST_F(Dex2oatLayoutTest,TestLayoutMultipleProfiles)881 TEST_F(Dex2oatLayoutTest, TestLayoutMultipleProfiles) {
882 std::string dex_location = GetScratchDir() + "/Dex.jar";
883 std::string odex_location = GetOdexDir() + "/Dex.odex";
884 std::string app_image_file = GetOdexDir() + "/Dex.art";
885 Copy(GetDexSrc2(), dex_location);
886
887 const std::string profile1_location = GetScratchDir() + "/primary.prof";
888 GenerateProfile(profile1_location, dex_location, /*num_classes=*/1, /*class_offset=*/0);
889 CompileProfileOdex(dex_location,
890 odex_location,
891 app_image_file,
892 /*use_fd=*/false,
893 {profile1_location});
894 uint32_t image_file_size_profile1 = GetImageObjectSectionSize(app_image_file);
895
896 const std::string profile2_location = GetScratchDir() + "/secondary.prof";
897 GenerateProfile(profile2_location, dex_location, /*num_classes=*/1, /*class_offset=*/1);
898 CompileProfileOdex(dex_location,
899 odex_location,
900 app_image_file,
901 /*use_fd=*/false,
902 {profile2_location});
903 uint32_t image_file_size_profile2 = GetImageObjectSectionSize(app_image_file);
904
905 CompileProfileOdex(dex_location,
906 odex_location,
907 app_image_file,
908 /*use_fd=*/false,
909 {profile1_location, profile2_location});
910 uint32_t image_file_size_multiple_profiles = GetImageObjectSectionSize(app_image_file);
911
912 CheckCompilerFilter(dex_location, odex_location, CompilerFilter::Filter::kSpeedProfile);
913
914 // The image file generated with multiple profiles should be larger than any image file generated
915 // with each profile.
916 ASSERT_GT(image_file_size_multiple_profiles, image_file_size_profile1);
917 ASSERT_GT(image_file_size_multiple_profiles, image_file_size_profile2);
918 }
919
TEST_F(Dex2oatLayoutTest,TestLayoutMultipleProfilesChecksumMismatch)920 TEST_F(Dex2oatLayoutTest, TestLayoutMultipleProfilesChecksumMismatch) {
921 std::string dex_location = GetScratchDir() + "/Dex.jar";
922
923 // Create two profiles whose dex locations are the same but checksums are different.
924 Copy(GetDexSrc1(), dex_location);
925 const std::string profile_old = GetScratchDir() + "/profile_old.prof";
926 GenerateProfile(profile_old, dex_location, /*num_classes=*/1, /*class_offset=*/0);
927
928 Copy(GetDexSrc2(), dex_location);
929 const std::string profile_new = GetScratchDir() + "/profile_new.prof";
930 GenerateProfile(profile_new, dex_location, /*num_classes=*/1, /*class_offset=*/0);
931
932 // Create an empty profile for reference.
933 const std::string profile_empty = GetScratchDir() + "/profile_empty.prof";
934 GenerateProfile(profile_empty, dex_location, /*num_classes=*/0, /*class_offset=*/0);
935
936 std::string odex_location = GetOdexDir() + "/Dex.odex";
937 std::string app_image_file = GetOdexDir() + "/Dex.art";
938
939 // This should produce a normal image because only `profile_new` is used and it has the right
940 // checksum.
941 CompileProfileOdex(dex_location,
942 odex_location,
943 app_image_file,
944 /*use_fd=*/false,
945 {profile_new, profile_old});
946 uint32_t image_size_right_checksum = GetImageObjectSectionSize(app_image_file);
947
948 // This should produce an empty image because only `profile_old` is used and it has the wrong
949 // checksum. Note that dex2oat does not abort compilation when the profile verification fails
950 // (b/62602192, b/65260586).
951 CompileProfileOdex(dex_location,
952 odex_location,
953 app_image_file,
954 /*use_fd=*/false,
955 {profile_old, profile_new});
956 uint32_t image_size_wrong_checksum = GetImageObjectSectionSize(app_image_file);
957
958 // Create an empty image using an empty profile for reference.
959 CompileProfileOdex(dex_location,
960 odex_location,
961 app_image_file,
962 /*use_fd=*/false,
963 {profile_empty});
964 uint32_t image_size_empty = GetImageObjectSectionSize(app_image_file);
965
966 EXPECT_GT(image_size_right_checksum, image_size_empty);
967 EXPECT_EQ(image_size_wrong_checksum, image_size_empty);
968 }
969
TEST_F(Dex2oatLayoutTest,TestVdexLayout)970 TEST_F(Dex2oatLayoutTest, TestVdexLayout) { RunTestVDex(); }
971
972 class Dex2oatWatchdogTest : public Dex2oatTest {
973 protected:
RunTest(bool expect_success,const std::vector<std::string> & extra_args={})974 void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {
975 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
976 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
977
978 Copy(GetTestDexFileName(), dex_location);
979
980 std::vector<std::string> copy(extra_args);
981
982 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
983 copy.push_back("--swap-file=" + swap_location);
984 copy.push_back("-j512"); // Excessive idle threads just slow down dex2oat.
985 ASSERT_TRUE(GenerateOdexForTest(
986 dex_location, odex_location, CompilerFilter::kSpeed, copy, expect_success));
987 }
988
GetTestDexFileName()989 std::string GetTestDexFileName() { return GetDexSrc1(); }
990 };
991
TEST_F(Dex2oatWatchdogTest,TestWatchdogOK)992 TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
993 // Check with default.
994 RunTest(true);
995
996 // Check with ten minutes.
997 RunTest(true, {"--watchdog-timeout=600000"});
998 }
999
TEST_F(Dex2oatWatchdogTest,TestWatchdogTrigger)1000 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
1001 // This test is frequently interrupted by signal_dumper on host (x86);
1002 // disable it while we investigate (b/121352534).
1003 TEST_DISABLED_FOR_X86();
1004
1005 // The watchdog is independent of dex2oat and will not delete intermediates. It is possible
1006 // that the compilation succeeds and the file is completely written by the time the watchdog
1007 // kills dex2oat (but the dex2oat threads must have been scheduled pretty badly).
1008 test_accepts_odex_file_on_failure = true;
1009
1010 // Check with ten milliseconds.
1011 RunTest(false, {"--watchdog-timeout=10"});
1012 }
1013
1014 class Dex2oatReturnCodeTest : public Dex2oatTest {
1015 protected:
RunTest(const std::vector<std::string> & extra_args={})1016 int RunTest(const std::vector<std::string>& extra_args = {}) {
1017 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
1018 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
1019
1020 Copy(GetTestDexFileName(), dex_location);
1021
1022 std::string error_msg;
1023 return GenerateOdexForTestWithStatus(
1024 {dex_location}, odex_location, CompilerFilter::kSpeed, &error_msg, extra_args);
1025 }
1026
GetTestDexFileName()1027 std::string GetTestDexFileName() { return GetDexSrc1(); }
1028 };
1029
1030 class Dex2oatClassLoaderContextTest : public Dex2oatTest {
1031 protected:
RunTest(const char * class_loader_context,const char * expected_classpath_key,bool expected_success,bool use_second_source=false,bool generate_image=false)1032 void RunTest(const char* class_loader_context,
1033 const char* expected_classpath_key,
1034 bool expected_success,
1035 bool use_second_source = false,
1036 bool generate_image = false) {
1037 std::string dex_location = GetUsedDexLocation();
1038 std::string odex_location = GetUsedOatLocation();
1039
1040 Copy(use_second_source ? GetDexSrc2() : GetDexSrc1(), dex_location);
1041
1042 std::string error_msg;
1043 std::vector<std::string> extra_args;
1044 if (class_loader_context != nullptr) {
1045 extra_args.push_back(std::string("--class-loader-context=") + class_loader_context);
1046 }
1047 if (generate_image) {
1048 extra_args.push_back(std::string("--app-image-file=") + GetUsedImageLocation());
1049 }
1050 auto check_oat = [expected_classpath_key](const OatFile& oat_file) {
1051 ASSERT_TRUE(expected_classpath_key != nullptr);
1052 const char* classpath = oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey);
1053 ASSERT_TRUE(classpath != nullptr);
1054 ASSERT_STREQ(expected_classpath_key, classpath);
1055 };
1056
1057 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1058 odex_location,
1059 CompilerFilter::kVerify,
1060 extra_args,
1061 expected_success,
1062 /*use_fd=*/false,
1063 /*use_zip_fd=*/false,
1064 check_oat));
1065 }
1066
GetUsedDexLocation()1067 std::string GetUsedDexLocation() { return GetScratchDir() + "/Context.jar"; }
1068
GetUsedOatLocation()1069 std::string GetUsedOatLocation() { return GetOdexDir() + "/Context.odex"; }
1070
GetUsedImageLocation()1071 std::string GetUsedImageLocation() { return GetOdexDir() + "/Context.art"; }
1072
1073 const char* kEmptyClassPathKey = "PCL[]";
1074 };
1075
TEST_F(Dex2oatClassLoaderContextTest,InvalidContext)1076 TEST_F(Dex2oatClassLoaderContextTest, InvalidContext) {
1077 RunTest("Invalid[]", /*expected_classpath_key*/ nullptr, /*expected_success*/ false);
1078 }
1079
TEST_F(Dex2oatClassLoaderContextTest,EmptyContext)1080 TEST_F(Dex2oatClassLoaderContextTest, EmptyContext) {
1081 RunTest("PCL[]", kEmptyClassPathKey, /*expected_success*/ true);
1082 }
1083
TEST_F(Dex2oatClassLoaderContextTest,ContextWithTheSourceDexFiles)1084 TEST_F(Dex2oatClassLoaderContextTest, ContextWithTheSourceDexFiles) {
1085 std::string context = "PCL[" + GetUsedDexLocation() + "]";
1086 RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
1087 }
1088
TEST_F(Dex2oatClassLoaderContextTest,ContextWithOtherDexFiles)1089 TEST_F(Dex2oatClassLoaderContextTest, ContextWithOtherDexFiles) {
1090 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Nested");
1091
1092 uint32_t expected_checksum = DexFileLoader::GetMultiDexChecksum(dex_files);
1093
1094 std::string context = "PCL[" + dex_files[0]->GetLocation() + "]";
1095 std::string expected_classpath_key =
1096 "PCL[" + dex_files[0]->GetLocation() + "*" + std::to_string(expected_checksum) + "]";
1097 RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1098 }
1099
TEST_F(Dex2oatClassLoaderContextTest,ContextWithResourceOnlyDexFiles)1100 TEST_F(Dex2oatClassLoaderContextTest, ContextWithResourceOnlyDexFiles) {
1101 std::string resource_only_classpath = GetScratchDir() + "/resource_only_classpath.jar";
1102 Copy(GetResourceOnlySrc1(), resource_only_classpath);
1103
1104 std::string context = "PCL[" + resource_only_classpath + "]";
1105 // Expect an empty context because resource only dex files cannot be open.
1106 RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
1107 }
1108
TEST_F(Dex2oatClassLoaderContextTest,ContextWithNotExistentDexFiles)1109 TEST_F(Dex2oatClassLoaderContextTest, ContextWithNotExistentDexFiles) {
1110 std::string context = "PCL[does_not_exists.dex]";
1111 // Expect an empty context because stripped dex files cannot be open.
1112 RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
1113 }
1114
TEST_F(Dex2oatClassLoaderContextTest,ChainContext)1115 TEST_F(Dex2oatClassLoaderContextTest, ChainContext) {
1116 std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1117 std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1118
1119 std::string context =
1120 "PCL[" + GetTestDexFileName("Nested") + "];" + "DLC[" + GetTestDexFileName("MultiDex") + "]";
1121 std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "];" +
1122 "DLC[" + CreateClassPathWithChecksums(dex_files2) + "]";
1123
1124 RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1125 }
1126
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSharedLibrary)1127 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibrary) {
1128 std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1129 std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1130
1131 std::string context =
1132 "PCL[" + GetTestDexFileName("Nested") + "]" + "{PCL[" + GetTestDexFileName("MultiDex") + "]}";
1133 std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1134 "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}";
1135 RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1136 }
1137
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSharedLibraryAndImage)1138 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibraryAndImage) {
1139 std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1140 std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1141
1142 std::string context =
1143 "PCL[" + GetTestDexFileName("Nested") + "]" + "{PCL[" + GetTestDexFileName("MultiDex") + "]}";
1144 std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1145 "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}";
1146 RunTest(context.c_str(),
1147 expected_classpath_key.c_str(),
1148 /*expected_success=*/true,
1149 /*use_second_source=*/false,
1150 /*generate_image=*/true);
1151 }
1152
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSameSharedLibrariesAndImage)1153 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSameSharedLibrariesAndImage) {
1154 std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1155 std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1156
1157 std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" + "{PCL[" +
1158 GetTestDexFileName("MultiDex") + "]" + "#PCL[" +
1159 GetTestDexFileName("MultiDex") + "]}";
1160 std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1161 "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]" +
1162 "#PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}";
1163 RunTest(context.c_str(),
1164 expected_classpath_key.c_str(),
1165 /*expected_success=*/true,
1166 /*use_second_source=*/false,
1167 /*generate_image=*/true);
1168 }
1169
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSharedLibrariesDependenciesAndImage)1170 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibrariesDependenciesAndImage) {
1171 std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1172 std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1173
1174 std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" + "{PCL[" +
1175 GetTestDexFileName("MultiDex") + "]" + "{PCL[" +
1176 GetTestDexFileName("Nested") + "]}}";
1177 std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1178 "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]" +
1179 "{PCL[" + CreateClassPathWithChecksums(dex_files1) + "]}}";
1180 RunTest(context.c_str(),
1181 expected_classpath_key.c_str(),
1182 /*expected_success=*/true,
1183 /*use_second_source=*/false,
1184 /*generate_image=*/true);
1185 }
1186
1187 class Dex2oatDeterminism : public Dex2oatTest {};
1188
TEST_F(Dex2oatDeterminism,UnloadCompile)1189 TEST_F(Dex2oatDeterminism, UnloadCompile) {
1190 Runtime* const runtime = Runtime::Current();
1191 std::string out_dir = GetScratchDir();
1192 const std::string base_oat_name = out_dir + "/base.oat";
1193 const std::string base_vdex_name = out_dir + "/base.vdex";
1194 const std::string unload_oat_name = out_dir + "/unload.oat";
1195 const std::string unload_vdex_name = out_dir + "/unload.vdex";
1196 const std::string no_unload_oat_name = out_dir + "/nounload.oat";
1197 const std::string no_unload_vdex_name = out_dir + "/nounload.vdex";
1198 std::string error_msg;
1199 const std::vector<gc::space::ImageSpace*>& spaces = runtime->GetHeap()->GetBootImageSpaces();
1200 ASSERT_GT(spaces.size(), 0u);
1201 const std::string image_location = spaces[0]->GetImageLocation();
1202 // Without passing in an app image, it will unload in between compilations.
1203 const int res =
1204 GenerateOdexForTestWithStatus(GetLibCoreDexFileNames(),
1205 base_oat_name,
1206 CompilerFilter::Filter::kVerify,
1207 &error_msg,
1208 {"--force-determinism", "--avoid-storing-invocation"});
1209 ASSERT_EQ(res, 0);
1210 Copy(base_oat_name, unload_oat_name);
1211 Copy(base_vdex_name, unload_vdex_name);
1212 std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str()));
1213 std::unique_ptr<File> unload_vdex(OS::OpenFileForReading(unload_vdex_name.c_str()));
1214 ASSERT_TRUE(unload_oat != nullptr);
1215 ASSERT_TRUE(unload_vdex != nullptr);
1216 EXPECT_GT(unload_oat->GetLength(), 0u);
1217 EXPECT_GT(unload_vdex->GetLength(), 0u);
1218 // Regenerate with an app image to disable the dex2oat unloading and verify that the output is
1219 // the same.
1220 const int res2 = GenerateOdexForTestWithStatus(
1221 GetLibCoreDexFileNames(),
1222 base_oat_name,
1223 CompilerFilter::Filter::kVerify,
1224 &error_msg,
1225 {"--force-determinism", "--avoid-storing-invocation", "--compile-individually"});
1226 ASSERT_EQ(res2, 0);
1227 Copy(base_oat_name, no_unload_oat_name);
1228 Copy(base_vdex_name, no_unload_vdex_name);
1229 std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str()));
1230 std::unique_ptr<File> no_unload_vdex(OS::OpenFileForReading(no_unload_vdex_name.c_str()));
1231 ASSERT_TRUE(no_unload_oat != nullptr);
1232 ASSERT_TRUE(no_unload_vdex != nullptr);
1233 EXPECT_GT(no_unload_oat->GetLength(), 0u);
1234 EXPECT_GT(no_unload_vdex->GetLength(), 0u);
1235 // Verify that both of the files are the same (odex and vdex).
1236 EXPECT_EQ(unload_oat->GetLength(), no_unload_oat->GetLength());
1237 EXPECT_EQ(unload_vdex->GetLength(), no_unload_vdex->GetLength());
1238 EXPECT_EQ(unload_oat->Compare(no_unload_oat.get()), 0)
1239 << unload_oat_name << " " << no_unload_oat_name;
1240 EXPECT_EQ(unload_vdex->Compare(no_unload_vdex.get()), 0)
1241 << unload_vdex_name << " " << no_unload_vdex_name;
1242 }
1243
1244 class Dex2oatVerifierAbort : public Dex2oatTest {};
1245
TEST_F(Dex2oatVerifierAbort,HardFail)1246 TEST_F(Dex2oatVerifierAbort, HardFail) {
1247 // Use VerifierDeps as it has hard-failing classes.
1248 std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDeps"));
1249 std::string out_dir = GetScratchDir();
1250 const std::string base_oat_name = out_dir + "/base.oat";
1251 std::string error_msg;
1252 const int res_fail = GenerateOdexForTestWithStatus({dex->GetLocation()},
1253 base_oat_name,
1254 CompilerFilter::Filter::kVerify,
1255 &error_msg,
1256 {"--abort-on-hard-verifier-error"});
1257 EXPECT_NE(0, res_fail);
1258
1259 const int res_no_fail = GenerateOdexForTestWithStatus({dex->GetLocation()},
1260 base_oat_name,
1261 CompilerFilter::Filter::kVerify,
1262 &error_msg,
1263 {"--no-abort-on-hard-verifier-error"});
1264 EXPECT_EQ(0, res_no_fail);
1265 }
1266
1267 class Dex2oatDedupeCode : public Dex2oatTest {};
1268
TEST_F(Dex2oatDedupeCode,DedupeTest)1269 TEST_F(Dex2oatDedupeCode, DedupeTest) {
1270 // Use MyClassNatives. It has lots of native methods that will produce deduplicate-able code.
1271 std::unique_ptr<const DexFile> dex(OpenTestDexFile("MyClassNatives"));
1272 std::string out_dir = GetScratchDir();
1273 const std::string base_oat_name = out_dir + "/base.oat";
1274 size_t no_dedupe_size = 0;
1275 ASSERT_TRUE(
1276 GenerateOdexForTest(dex->GetLocation(),
1277 base_oat_name,
1278 CompilerFilter::Filter::kSpeed,
1279 {"--deduplicate-code=false"},
1280 /*expect_success=*/true,
1281 /*use_fd=*/false,
1282 /*use_zip_fd=*/false,
1283 [&no_dedupe_size](const OatFile& o) { no_dedupe_size = o.Size(); }));
1284
1285 size_t dedupe_size = 0;
1286 ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
1287 base_oat_name,
1288 CompilerFilter::Filter::kSpeed,
1289 {"--deduplicate-code=true"},
1290 /*expect_success=*/true,
1291 /*use_fd=*/false,
1292 /*use_zip_fd=*/false,
1293 [&dedupe_size](const OatFile& o) { dedupe_size = o.Size(); }));
1294
1295 EXPECT_LT(dedupe_size, no_dedupe_size);
1296 }
1297
TEST_F(Dex2oatTest,UncompressedTest)1298 TEST_F(Dex2oatTest, UncompressedTest) {
1299 std::unique_ptr<const DexFile> dex(OpenTestDexFile("MainUncompressedAligned"));
1300 std::string out_dir = GetScratchDir();
1301 const std::string base_oat_name = out_dir + "/base.oat";
1302 ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
1303 base_oat_name,
1304 CompilerFilter::Filter::kVerify,
1305 {},
1306 /*expect_success=*/true,
1307 /*use_fd=*/false,
1308 /*use_zip_fd=*/false,
1309 [](const OatFile& o) { CHECK(!o.ContainsDexCode()); }));
1310 }
1311
TEST_F(Dex2oatTest,MissingBootImageTest)1312 TEST_F(Dex2oatTest, MissingBootImageTest) {
1313 std::string out_dir = GetScratchDir();
1314 const std::string base_oat_name = out_dir + "/base.oat";
1315 // The compilation should succeed even without the boot image.
1316 ASSERT_TRUE(GenerateOdexForTest(
1317 {GetTestDexFileName("MainUncompressedAligned")},
1318 base_oat_name,
1319 CompilerFilter::Filter::kVerify,
1320 // Note: Extra options go last and the second `--boot-image` option overrides the first.
1321 {"--boot-image=/nonx/boot.art"}));
1322 }
1323
TEST_F(Dex2oatTest,EmptyUncompressedDexTest)1324 TEST_F(Dex2oatTest, EmptyUncompressedDexTest) {
1325 std::string out_dir = GetScratchDir();
1326 const std::string base_oat_name = out_dir + "/base.oat";
1327 std::string error_msg;
1328 int status = GenerateOdexForTestWithStatus({GetTestDexFileName("MainEmptyUncompressed")},
1329 base_oat_name,
1330 CompilerFilter::Filter::kVerify,
1331 &error_msg,
1332 {},
1333 /*use_fd*/ false);
1334 // Expect to fail with code 1 and not SIGSEGV or SIGABRT.
1335 ASSERT_TRUE(WIFEXITED(status));
1336 ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg;
1337 }
1338
TEST_F(Dex2oatTest,EmptyUncompressedAlignedDexTest)1339 TEST_F(Dex2oatTest, EmptyUncompressedAlignedDexTest) {
1340 std::string out_dir = GetScratchDir();
1341 const std::string base_oat_name = out_dir + "/base.oat";
1342 std::string error_msg;
1343 int status = GenerateOdexForTestWithStatus({GetTestDexFileName("MainEmptyUncompressedAligned")},
1344 base_oat_name,
1345 CompilerFilter::Filter::kVerify,
1346 &error_msg,
1347 {},
1348 /*use_fd*/ false);
1349 // Expect to fail with code 1 and not SIGSEGV or SIGABRT.
1350 ASSERT_TRUE(WIFEXITED(status));
1351 ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg;
1352 }
1353
TEST_F(Dex2oatTest,StderrLoggerOutput)1354 TEST_F(Dex2oatTest, StderrLoggerOutput) {
1355 std::string dex_location = GetScratchDir() + "/Dex2OatStderrLoggerTest.jar";
1356 std::string odex_location = GetOdexDir() + "/Dex2OatStderrLoggerTest.odex";
1357
1358 // Test file doesn't matter.
1359 Copy(GetDexSrc1(), dex_location);
1360
1361 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1362 odex_location,
1363 CompilerFilter::kVerify,
1364 {"--runtime-arg", "-Xuse-stderr-logger"},
1365 true));
1366 // Look for some random part of dex2oat logging. With the stderr logger this should be captured,
1367 // even on device.
1368 EXPECT_NE(std::string::npos, output_.find("dex2oat took"));
1369 }
1370
TEST_F(Dex2oatTest,VerifyCompilationReason)1371 TEST_F(Dex2oatTest, VerifyCompilationReason) {
1372 std::string dex_location = GetScratchDir() + "/Dex2OatCompilationReason.jar";
1373 std::string odex_location = GetOdexDir() + "/Dex2OatCompilationReason.odex";
1374
1375 // Test file doesn't matter.
1376 Copy(GetDexSrc1(), dex_location);
1377
1378 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1379 odex_location,
1380 CompilerFilter::kVerify,
1381 {"--compilation-reason=install"},
1382 true));
1383 std::string error_msg;
1384 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
1385 odex_location,
1386 odex_location,
1387 /*executable=*/false,
1388 /*low_4gb=*/false,
1389 dex_location,
1390 &error_msg));
1391 ASSERT_TRUE(odex_file != nullptr);
1392 ASSERT_STREQ("install", odex_file->GetCompilationReason());
1393 }
1394
TEST_F(Dex2oatTest,VerifyNoCompilationReason)1395 TEST_F(Dex2oatTest, VerifyNoCompilationReason) {
1396 std::string dex_location = GetScratchDir() + "/Dex2OatNoCompilationReason.jar";
1397 std::string odex_location = GetOdexDir() + "/Dex2OatNoCompilationReason.odex";
1398
1399 // Test file doesn't matter.
1400 Copy(GetDexSrc1(), dex_location);
1401
1402 ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kVerify, {}, true));
1403 std::string error_msg;
1404 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
1405 odex_location,
1406 odex_location,
1407 /*executable=*/false,
1408 /*low_4gb=*/false,
1409 dex_location,
1410 &error_msg));
1411 ASSERT_TRUE(odex_file != nullptr);
1412 ASSERT_EQ(nullptr, odex_file->GetCompilationReason());
1413 }
1414
TEST_F(Dex2oatTest,DontExtract)1415 TEST_F(Dex2oatTest, DontExtract) {
1416 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
1417 std::string error_msg;
1418 const std::string out_dir = GetScratchDir();
1419 const std::string dex_location = dex->GetLocation();
1420 const std::string odex_location = out_dir + "/base.oat";
1421 const std::string vdex_location = out_dir + "/base.vdex";
1422 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1423 odex_location,
1424 CompilerFilter::Filter::kVerify,
1425 {"--copy-dex-files=false"},
1426 /*expect_success=*/true,
1427 /*use_fd=*/false,
1428 /*use_zip_fd=*/false,
1429 [](const OatFile&) {}));
1430 {
1431 // Check the vdex doesn't have dex.
1432 std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location,
1433 /*writable=*/false,
1434 /*low_4gb=*/false,
1435 &error_msg));
1436 ASSERT_TRUE(vdex != nullptr);
1437 EXPECT_FALSE(vdex->HasDexSection()) << output_;
1438 }
1439 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
1440 odex_location,
1441 odex_location,
1442 /*executable=*/false,
1443 /*low_4gb=*/false,
1444 dex_location,
1445 &error_msg));
1446 ASSERT_TRUE(odex_file != nullptr) << dex_location;
1447 std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
1448 ASSERT_EQ(oat_dex_files.size(), 1u);
1449 // Verify that the oat file can still open the dex files.
1450 for (const OatDexFile* oat_dex : oat_dex_files) {
1451 std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
1452 ASSERT_TRUE(dex_file != nullptr) << error_msg;
1453 }
1454 // Create a dm file and use it to verify.
1455 // Add produced artifacts to a zip file that doesn't contain the classes.dex.
1456 ScratchFile dm_file;
1457 {
1458 std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_location.c_str()));
1459 ASSERT_TRUE(vdex_file != nullptr);
1460 ASSERT_GT(vdex_file->GetLength(), 0u);
1461 FILE* file = fdopen(DupCloexec(dm_file.GetFd()), "w+b");
1462 ZipWriter writer(file);
1463 auto write_all_bytes = [&](File* file) {
1464 std::unique_ptr<uint8_t[]> bytes(new uint8_t[file->GetLength()]);
1465 ASSERT_TRUE(file->ReadFully(&bytes[0], file->GetLength()));
1466 ASSERT_GE(writer.WriteBytes(&bytes[0], file->GetLength()), 0);
1467 };
1468 // Add vdex to zip.
1469 writer.StartEntry(VdexFile::kVdexNameInDmFile, ZipWriter::kCompress);
1470 write_all_bytes(vdex_file.get());
1471 writer.FinishEntry();
1472 writer.Finish();
1473 ASSERT_EQ(dm_file.GetFile()->Flush(), 0);
1474 }
1475
1476 auto generate_and_check = [&](CompilerFilter::Filter filter) {
1477 output_.clear();
1478 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1479 odex_location,
1480 filter,
1481 {"--dump-timings",
1482 "--dm-file=" + dm_file.GetFilename(),
1483 // Pass -Xuse-stderr-logger have dex2oat output in output_ on
1484 // target.
1485 "--runtime-arg",
1486 "-Xuse-stderr-logger"},
1487 /*expect_success=*/true,
1488 /*use_fd=*/false,
1489 /*use_zip_fd=*/false,
1490 [](const OatFile& o) { CHECK(o.ContainsDexCode()); }));
1491 // Check the output for "Fast verify", this is printed from --dump-timings.
1492 std::istringstream iss(output_);
1493 std::string line;
1494 bool found_fast_verify = false;
1495 const std::string kFastVerifyString = "Fast Verify";
1496 while (std::getline(iss, line) && !found_fast_verify) {
1497 found_fast_verify = found_fast_verify || line.find(kFastVerifyString) != std::string::npos;
1498 }
1499 EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_;
1500 };
1501
1502 // Use verify compiler filter to check that FastVerify works for that filter too.
1503 generate_and_check(CompilerFilter::Filter::kVerify);
1504 }
1505
1506 // Test that compact dex generation with invalid dex files doesn't crash dex2oat. b/75970654
TEST_F(Dex2oatTest,CompactDexInvalidSource)1507 TEST_F(Dex2oatTest, CompactDexInvalidSource) {
1508 ScratchFile invalid_dex;
1509 {
1510 FILE* file = fdopen(DupCloexec(invalid_dex.GetFd()), "w+b");
1511 ZipWriter writer(file);
1512 writer.StartEntry("classes.dex", ZipWriter::kAlign32);
1513 DexFile::Header header = {};
1514 StandardDexFile::WriteMagic(header.magic_.data());
1515 StandardDexFile::WriteCurrentVersion(header.magic_.data());
1516 header.file_size_ = 4 * KB;
1517 header.data_size_ = 4 * KB;
1518 header.data_off_ = 10 * MB;
1519 header.map_off_ = 10 * MB;
1520 header.class_defs_off_ = 10 * MB;
1521 header.class_defs_size_ = 10000;
1522 ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
1523 writer.FinishEntry();
1524 writer.Finish();
1525 ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
1526 }
1527 const std::string& dex_location = invalid_dex.GetFilename();
1528 const std::string odex_location = GetOdexDir() + "/output.odex";
1529 std::string error_msg;
1530 int status = GenerateOdexForTestWithStatus(
1531 {dex_location}, odex_location, CompilerFilter::kVerify, &error_msg, {});
1532 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
1533 }
1534
1535 // Retain the header magic for the now removed compact dex files.
1536 class LegacyCompactDexFile : public DexFile {
1537 public:
1538 static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
1539 static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
1540
WriteMagic(uint8_t * magic)1541 static void WriteMagic(uint8_t* magic) {
1542 std::copy_n(kDexMagic, kDexMagicSize, magic);
1543 }
1544
WriteCurrentVersion(uint8_t * magic)1545 static void WriteCurrentVersion(uint8_t* magic) {
1546 std::copy_n(kDexMagicVersion, kDexVersionLen, magic + kDexMagicSize);
1547 }
1548 };
1549
1550 // Test that dex2oat with a legacy CompactDex file in the APK fails.
TEST_F(Dex2oatTest,CompactDexInZip)1551 TEST_F(Dex2oatTest, CompactDexInZip) {
1552 LegacyCompactDexFile::Header header = {};
1553 LegacyCompactDexFile::WriteMagic(header.magic_.data());
1554 LegacyCompactDexFile::WriteCurrentVersion(header.magic_.data());
1555 header.file_size_ = sizeof(LegacyCompactDexFile::Header);
1556 header.map_off_ = 10 * MB;
1557 header.class_defs_off_ = 10 * MB;
1558 header.class_defs_size_ = 10000;
1559 // Create a zip containing the invalid dex.
1560 ScratchFile invalid_dex_zip;
1561 {
1562 FILE* file = fdopen(DupCloexec(invalid_dex_zip.GetFd()), "w+b");
1563 ZipWriter writer(file);
1564 writer.StartEntry("classes.dex", ZipWriter::kCompress);
1565 ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
1566 writer.FinishEntry();
1567 writer.Finish();
1568 ASSERT_EQ(invalid_dex_zip.GetFile()->Flush(), 0);
1569 }
1570 // Create the dex file directly.
1571 ScratchFile invalid_dex;
1572 {
1573 ASSERT_GE(invalid_dex.GetFile()->WriteFully(&header, sizeof(header)), 0);
1574 ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
1575 }
1576 std::string error_msg;
1577 int status = 0u;
1578
1579 status = GenerateOdexForTestWithStatus({invalid_dex_zip.GetFilename()},
1580 GetOdexDir() + "/output_apk.odex",
1581 CompilerFilter::kVerify,
1582 &error_msg,
1583 {});
1584 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
1585
1586 status = GenerateOdexForTestWithStatus({invalid_dex.GetFilename()},
1587 GetOdexDir() + "/output.odex",
1588 CompilerFilter::kVerify,
1589 &error_msg,
1590 {});
1591 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
1592 }
1593
TEST_F(Dex2oatWithExpectedFilterTest,AppImageNoProfile)1594 TEST_F(Dex2oatWithExpectedFilterTest, AppImageNoProfile) {
1595 // Set the expected filter.
1596 expected_filter_ = CompilerFilter::Filter::kVerify;
1597
1598 ScratchFile app_image_file;
1599 const std::string out_dir = GetScratchDir();
1600 const std::string odex_location = out_dir + "/base.odex";
1601 ASSERT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
1602 odex_location,
1603 CompilerFilter::Filter::kSpeedProfile,
1604 {"--app-image-fd=" + std::to_string(app_image_file.GetFd())},
1605 /*expect_success=*/true,
1606 /*use_fd=*/false,
1607 /*use_zip_fd=*/false,
1608 [](const OatFile&) {}));
1609 // Open our generated oat file.
1610 std::string error_msg;
1611 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
1612 odex_location,
1613 odex_location,
1614 /*executable=*/false,
1615 /*low_4gb=*/false,
1616 &error_msg));
1617 ASSERT_TRUE(odex_file != nullptr);
1618 ImageHeader header = {};
1619 ASSERT_TRUE(app_image_file.GetFile()->PreadFully(reinterpret_cast<void*>(&header),
1620 sizeof(header),
1621 /*offset*/ 0u))
1622 << app_image_file.GetFile()->GetLength();
1623 EXPECT_GT(header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u);
1624 EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtMethods).Size(), 0u);
1625 EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u);
1626 }
1627
TEST_F(Dex2oatTest,ZipFd)1628 TEST_F(Dex2oatTest, ZipFd) {
1629 std::string zip_location = GetTestDexFileName("MainUncompressedAligned");
1630 std::unique_ptr<File> dex_file(OS::OpenFileForReading(zip_location.c_str()));
1631 std::vector<std::string> extra_args{
1632 StringPrintf("--zip-fd=%d", dex_file->Fd()),
1633 "--zip-location=" + zip_location,
1634 };
1635 std::string out_dir = GetScratchDir();
1636 const std::string base_oat_name = out_dir + "/base.oat";
1637 ASSERT_TRUE(GenerateOdexForTest(zip_location,
1638 base_oat_name,
1639 CompilerFilter::Filter::kVerify,
1640 extra_args,
1641 /*expect_success=*/true,
1642 /*use_fd=*/false,
1643 /*use_zip_fd=*/true));
1644 }
1645
TEST_F(Dex2oatWithExpectedFilterTest,AppImageEmptyDex)1646 TEST_F(Dex2oatWithExpectedFilterTest, AppImageEmptyDex) {
1647 // Set the expected filter.
1648 expected_filter_ = CompilerFilter::Filter::kVerify;
1649
1650 // Create a profile with the startup method marked.
1651 ScratchFile profile_file;
1652 ScratchFile temp_dex;
1653 const std::string& dex_location = temp_dex.GetFilename();
1654 std::vector<uint16_t> methods;
1655 std::vector<dex::TypeIndex> classes;
1656 {
1657 MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("StringLiterals"), [&](DexFile* dex) {
1658 // Modify the header to make the dex file valid but empty.
1659 DexFile::Header* header = const_cast<DexFile::Header*>(&dex->GetHeader());
1660 header->string_ids_size_ = 0;
1661 header->string_ids_off_ = 0;
1662 header->type_ids_size_ = 0;
1663 header->type_ids_off_ = 0;
1664 header->proto_ids_size_ = 0;
1665 header->proto_ids_off_ = 0;
1666 header->field_ids_size_ = 0;
1667 header->field_ids_off_ = 0;
1668 header->method_ids_size_ = 0;
1669 header->method_ids_off_ = 0;
1670 header->class_defs_size_ = 0;
1671 header->class_defs_off_ = 0;
1672 ASSERT_GT(header->file_size_,
1673 sizeof(*header) + sizeof(dex::MapList) + sizeof(dex::MapItem) * 2);
1674 // Move map list to be right after the header.
1675 header->map_off_ = header->header_size_;
1676 dex::MapList* map_list = const_cast<dex::MapList*>(dex->GetMapList());
1677 map_list->list_[0].type_ = DexFile::kDexTypeHeaderItem;
1678 map_list->list_[0].size_ = 1u;
1679 map_list->list_[0].offset_ = 0u;
1680 map_list->list_[1].type_ = DexFile::kDexTypeMapList;
1681 map_list->list_[1].size_ = 1u;
1682 map_list->list_[1].offset_ = header->map_off_;
1683 map_list->size_ = 2;
1684 header->data_off_ = header->map_off_;
1685 header->data_size_ = map_list->Size();
1686 header->SetDexContainer(0, header->file_size_);
1687 });
1688 }
1689 std::unique_ptr<const DexFile> dex_file(OpenDexFile(temp_dex.GetFilename().c_str()));
1690 const std::string out_dir = GetScratchDir();
1691 const std::string odex_location = out_dir + "/base.odex";
1692 const std::string app_image_location = out_dir + "/base.art";
1693 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1694 odex_location,
1695 CompilerFilter::Filter::kSpeedProfile,
1696 {"--app-image-file=" + app_image_location,
1697 "--resolve-startup-const-strings=true",
1698 "--profile-file=" + profile_file.GetFilename()},
1699 /*expect_success=*/true,
1700 /*use_fd=*/false,
1701 /*use_zip_fd=*/false,
1702 [](const OatFile&) {}));
1703 // Open our generated oat file.
1704 std::string error_msg;
1705 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
1706 odex_location,
1707 odex_location,
1708 /*executable=*/false,
1709 /*low_4gb=*/false,
1710 &error_msg));
1711 ASSERT_TRUE(odex_file != nullptr);
1712 }
1713
TEST_F(Dex2oatTest,DexFileFd)1714 TEST_F(Dex2oatTest, DexFileFd) {
1715 std::string error_msg;
1716 std::string zip_location = GetTestDexFileName("Main");
1717 std::unique_ptr<File> zip_file(OS::OpenFileForReading(zip_location.c_str()));
1718 ASSERT_NE(-1, zip_file->Fd());
1719
1720 std::unique_ptr<ZipArchive> zip_archive(
1721 ZipArchive::OpenFromFd(zip_file->Release(), zip_location.c_str(), &error_msg));
1722 ASSERT_TRUE(zip_archive != nullptr);
1723
1724 std::string entry_name = DexFileLoader::GetMultiDexClassesDexName(0);
1725 std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
1726 ASSERT_TRUE(entry != nullptr);
1727
1728 ScratchFile dex_file;
1729 const std::string& dex_location = dex_file.GetFilename();
1730 const std::string base_oat_name = GetScratchDir() + "/base.oat";
1731
1732 bool success = entry->ExtractToFile(*(dex_file.GetFile()), &error_msg);
1733 ASSERT_TRUE(success);
1734 ASSERT_EQ(0, lseek(dex_file.GetFd(), 0, SEEK_SET));
1735
1736 std::vector<std::string> extra_args{
1737 StringPrintf("--zip-fd=%d", dex_file.GetFd()),
1738 "--zip-location=" + dex_location,
1739 };
1740 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1741 base_oat_name,
1742 CompilerFilter::Filter::kVerify,
1743 extra_args,
1744 /*expect_success=*/true,
1745 /*use_fd=*/false,
1746 /*use_zip_fd=*/true));
1747 }
1748
TEST_F(Dex2oatTest,DontCopyPlainDex)1749 TEST_F(Dex2oatTest, DontCopyPlainDex) {
1750 std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDepsMulti"));
1751 std::string error_msg;
1752 const std::string out_dir = GetScratchDir();
1753 const std::string dex_location = dex->GetLocation();
1754 const std::string odex_location = out_dir + "/base.oat";
1755 const std::string vdex_location = out_dir + "/base.vdex";
1756 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1757 odex_location,
1758 CompilerFilter::Filter::kVerify,
1759 {},
1760 /*expect_success=*/true,
1761 /*use_fd=*/false,
1762 /*use_zip_fd=*/false,
1763 [](const OatFile&) {}));
1764
1765 // Check that the vdex doesn't have dex code.
1766 std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location,
1767 /*writable=*/false,
1768 /*low_4gb=*/false,
1769 &error_msg));
1770 ASSERT_TRUE(vdex != nullptr);
1771 EXPECT_FALSE(vdex->HasDexSection()) << output_;
1772 }
1773
TEST_F(Dex2oatTest,AppImageResolveStrings)1774 TEST_F(Dex2oatTest, AppImageResolveStrings) {
1775 using Hotness = ProfileCompilationInfo::MethodHotness;
1776 // Create a profile with the startup method marked.
1777 ScratchFile profile_file;
1778 ScratchFile temp_dex;
1779 const std::string& dex_location = temp_dex.GetFilename();
1780 std::vector<uint16_t> methods;
1781 std::vector<dex::TypeIndex> classes;
1782 {
1783 MutateDexFile(
1784 temp_dex.GetFile(), GetTestDexFileName("StringLiterals"), [&](DexFile* dex) {
1785 bool mutated_successfully = false;
1786 // Change the dex instructions to make an opcode that spans past the end of the code item.
1787 for (ClassAccessor accessor : dex->GetClasses()) {
1788 if (accessor.GetDescriptor() == std::string("LStringLiterals$StartupClass;")) {
1789 classes.push_back(accessor.GetClassIdx());
1790 }
1791 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1792 std::string method_name(dex->GetMethodName(dex->GetMethodId(method.GetIndex())));
1793 CodeItemInstructionAccessor instructions = method.GetInstructions();
1794 if (method_name == "startUpMethod2") {
1795 // Make an instruction that runs past the end of the code item and verify that it
1796 // doesn't cause dex2oat to crash.
1797 ASSERT_TRUE(instructions.begin() != instructions.end());
1798 DexInstructionIterator last_instruction = instructions.begin();
1799 for (auto dex_it = instructions.begin(); dex_it != instructions.end(); ++dex_it) {
1800 last_instruction = dex_it;
1801 }
1802 ASSERT_EQ(last_instruction->SizeInCodeUnits(), 1u);
1803 // Set the opcode to something that will go past the end of the code item.
1804 const_cast<Instruction&>(last_instruction.Inst())
1805 .SetOpcode(Instruction::CONST_STRING_JUMBO);
1806 mutated_successfully = true;
1807 // Test that the safe iterator doesn't go past the end.
1808 SafeDexInstructionIterator it2(instructions.begin(), instructions.end());
1809 while (!it2.IsErrorState()) {
1810 ++it2;
1811 }
1812 EXPECT_TRUE(it2 == last_instruction);
1813 EXPECT_TRUE(it2 < instructions.end());
1814 methods.push_back(method.GetIndex());
1815 mutated_successfully = true;
1816 } else if (method_name == "startUpMethod") {
1817 methods.push_back(method.GetIndex());
1818 }
1819 }
1820 }
1821 CHECK(mutated_successfully)
1822 << "Failed to find candidate code item with only one code unit in last instruction.";
1823 });
1824 }
1825 std::unique_ptr<const DexFile> dex_file(OpenDexFile(temp_dex.GetFilename().c_str()));
1826 {
1827 ASSERT_GT(classes.size(), 0u);
1828 ASSERT_GT(methods.size(), 0u);
1829 // Here, we build the profile from the method lists.
1830 ProfileCompilationInfo info;
1831 info.AddClassesForDex(dex_file.get(), classes.begin(), classes.end());
1832 info.AddMethodsForDex(Hotness::kFlagStartup, dex_file.get(), methods.begin(), methods.end());
1833 // Save the profile since we want to use it with dex2oat to produce an oat file.
1834 ASSERT_TRUE(info.Save(profile_file.GetFd()));
1835 }
1836 const std::string out_dir = GetScratchDir();
1837 const std::string odex_location = out_dir + "/base.odex";
1838 const std::string app_image_location = out_dir + "/base.art";
1839 ASSERT_TRUE(GenerateOdexForTest(dex_location,
1840 odex_location,
1841 CompilerFilter::Filter::kSpeedProfile,
1842 {"--app-image-file=" + app_image_location,
1843 "--resolve-startup-const-strings=true",
1844 "--profile-file=" + profile_file.GetFilename()},
1845 /*expect_success=*/true,
1846 /*use_fd=*/false,
1847 /*use_zip_fd=*/false,
1848 [](const OatFile&) {}));
1849 // Open our generated oat file.
1850 std::string error_msg;
1851 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
1852 odex_location,
1853 odex_location,
1854 /*executable=*/false,
1855 /*low_4gb=*/false,
1856 &error_msg));
1857 ASSERT_TRUE(odex_file != nullptr);
1858 // Check the strings in the app image intern table only contain the "startup" strigs.
1859 {
1860 ScopedObjectAccess soa(Thread::Current());
1861 std::unique_ptr<gc::space::ImageSpace> space = gc::space::ImageSpace::CreateFromAppImage(
1862 app_image_location.c_str(), odex_file.get(), &error_msg);
1863 ASSERT_TRUE(space != nullptr) << error_msg;
1864 std::set<std::string> seen;
1865 InternTable intern_table;
1866 intern_table.AddImageStringsToTable(
1867 space.get(), [&](InternTable::UnorderedSet& interns) REQUIRES_SHARED(Locks::mutator_lock_) {
1868 for (const GcRoot<mirror::String>& str : interns) {
1869 seen.insert(str.Read()->ToModifiedUtf8());
1870 }
1871 });
1872 // Normal methods
1873 EXPECT_TRUE(seen.find("Loading ") != seen.end());
1874 EXPECT_TRUE(seen.find("Starting up") != seen.end());
1875 EXPECT_TRUE(seen.find("abcd.apk") != seen.end());
1876 EXPECT_TRUE(seen.find("Unexpected error") == seen.end());
1877 EXPECT_TRUE(seen.find("Shutting down!") == seen.end());
1878 // Classes initializers
1879 EXPECT_TRUE(seen.find("Startup init") != seen.end());
1880 EXPECT_TRUE(seen.find("Other class init") == seen.end());
1881 // Expect the sets match.
1882 EXPECT_GE(seen.size(), seen.size());
1883
1884 // Verify what strings are marked as boot image.
1885 std::set<std::string> boot_image_strings;
1886 std::set<std::string> app_image_strings;
1887
1888 MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
1889 intern_table.VisitInterns(
1890 [&](const GcRoot<mirror::String>& root) REQUIRES_SHARED(Locks::mutator_lock_) {
1891 boot_image_strings.insert(root.Read()->ToModifiedUtf8());
1892 },
1893 /*visit_boot_images=*/true,
1894 /*visit_non_boot_images=*/false);
1895 intern_table.VisitInterns(
1896 [&](const GcRoot<mirror::String>& root) REQUIRES_SHARED(Locks::mutator_lock_) {
1897 app_image_strings.insert(root.Read()->ToModifiedUtf8());
1898 },
1899 /*visit_boot_images=*/false,
1900 /*visit_non_boot_images=*/true);
1901 EXPECT_EQ(boot_image_strings.size(), 0u);
1902 EXPECT_TRUE(app_image_strings == seen);
1903 }
1904 }
1905
TEST_F(Dex2oatClassLoaderContextTest,StoredClassLoaderContext)1906 TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) {
1907 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
1908 const std::string out_dir = GetScratchDir();
1909 const std::string odex_location = out_dir + "/base.odex";
1910 const std::string valid_context = "PCL[" + dex_files[0]->GetLocation() + "]";
1911 const std::string stored_context = "PCL[/system/not_real_lib.jar]";
1912 uint32_t checksum = DexFileLoader::GetMultiDexChecksum(dex_files);
1913 std::string expected_stored_context =
1914 "PCL[/system/not_real_lib.jar*" + std::to_string(checksum) + "]";
1915 // The class path should not be valid and should fail being stored.
1916 EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
1917 odex_location,
1918 CompilerFilter::Filter::kVerify,
1919 {"--class-loader-context=" + stored_context},
1920 /*expect_success=*/true,
1921 /*use_fd=*/false,
1922 /*use_zip_fd=*/false,
1923 [&](const OatFile& oat_file) {
1924 EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context)
1925 << output_;
1926 EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context)
1927 << output_;
1928 }));
1929 // The stored context should match what we expect even though it's invalid.
1930 EXPECT_TRUE(GenerateOdexForTest(
1931 GetTestDexFileName("ManyMethods"),
1932 odex_location,
1933 CompilerFilter::Filter::kVerify,
1934 {"--class-loader-context=" + valid_context,
1935 "--stored-class-loader-context=" + stored_context},
1936 /*expect_success=*/true,
1937 /*use_fd=*/false,
1938 /*use_zip_fd=*/false,
1939 [&](const OatFile& oat_file) {
1940 EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_;
1941 }));
1942 }
1943
1944 class Dex2oatISAFeaturesRuntimeDetectionTest : public Dex2oatTest {
1945 protected:
RunTest(const std::vector<std::string> & extra_args={})1946 void RunTest(const std::vector<std::string>& extra_args = {}) {
1947 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
1948 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
1949
1950 Copy(GetTestDexFileName(), dex_location);
1951
1952 ASSERT_TRUE(
1953 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, extra_args));
1954 }
1955
GetTestDexFileName()1956 std::string GetTestDexFileName() { return GetDexSrc1(); }
1957 };
1958
TEST_F(Dex2oatISAFeaturesRuntimeDetectionTest,TestCurrentRuntimeFeaturesAsDex2OatArguments)1959 TEST_F(Dex2oatISAFeaturesRuntimeDetectionTest, TestCurrentRuntimeFeaturesAsDex2OatArguments) {
1960 std::vector<std::string> argv;
1961 Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
1962 auto option_pos =
1963 std::find(std::begin(argv), std::end(argv), "--instruction-set-features=runtime");
1964 if (InstructionSetFeatures::IsRuntimeDetectionSupported()) {
1965 EXPECT_TRUE(kIsTargetBuild);
1966 EXPECT_NE(option_pos, std::end(argv));
1967 } else {
1968 EXPECT_EQ(option_pos, std::end(argv));
1969 }
1970
1971 RunTest();
1972 }
1973
1974 class LinkageTest : public Dex2oatTest {};
1975
TEST_F(LinkageTest,LinkageEnabled)1976 TEST_F(LinkageTest, LinkageEnabled) {
1977 TEST_DISABLED_FOR_TARGET();
1978 std::unique_ptr<const DexFile> dex(OpenTestDexFile("LinkageTest"));
1979 std::string out_dir = GetScratchDir();
1980 const std::string base_oat_name = out_dir + "/base.oat";
1981 std::string error_msg;
1982 const int res_fail =
1983 GenerateOdexForTestWithStatus({dex->GetLocation()},
1984 base_oat_name,
1985 CompilerFilter::Filter::kSpeed,
1986 &error_msg,
1987 {"--check-linkage-conditions", "--crash-on-linkage-violation"});
1988 EXPECT_NE(0, res_fail);
1989
1990 const int res_no_fail = GenerateOdexForTestWithStatus({dex->GetLocation()},
1991 base_oat_name,
1992 CompilerFilter::Filter::kSpeed,
1993 &error_msg,
1994 {"--check-linkage-conditions"});
1995 EXPECT_EQ(0, res_no_fail);
1996 }
1997
1998 // Regression test for bug 179221298.
TEST_F(Dex2oatTest,LoadOutOfDateOatFile)1999 TEST_F(Dex2oatTest, LoadOutOfDateOatFile) {
2000 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
2001 std::string out_dir = GetScratchDir();
2002 const std::string base_oat_name = out_dir + "/base.oat";
2003 ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
2004 base_oat_name,
2005 CompilerFilter::Filter::kSpeed,
2006 {"--deduplicate-code=false"},
2007 /*expect_success=*/true,
2008 /*use_fd=*/false,
2009 /*use_zip_fd=*/false));
2010
2011 // Check that we can open the oat file as executable.
2012 {
2013 std::string error_msg;
2014 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
2015 base_oat_name,
2016 base_oat_name,
2017 /*executable=*/true,
2018 /*low_4gb=*/false,
2019 dex->GetLocation(),
2020 &error_msg));
2021 ASSERT_TRUE(odex_file != nullptr) << error_msg;
2022 }
2023
2024 // Rewrite the oat file with wrong version and bogus contents.
2025 {
2026 std::unique_ptr<File> file(OS::OpenFileReadWrite(base_oat_name.c_str()));
2027 ASSERT_TRUE(file != nullptr);
2028 // Retrieve the offset and size of the embedded oat file.
2029 size_t oatdata_offset;
2030 size_t oatdata_size;
2031 {
2032 std::string error_msg;
2033 std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.get(),
2034 /*writable=*/false,
2035 /*program_header_only=*/true,
2036 /*low_4gb=*/false,
2037 &error_msg));
2038 ASSERT_TRUE(elf_file != nullptr) << error_msg;
2039 ASSERT_TRUE(elf_file->Load(file.get(),
2040 /*executable=*/false,
2041 /*low_4gb=*/false,
2042 /*reservation=*/nullptr,
2043 &error_msg))
2044 << error_msg;
2045 const uint8_t* base_address = elf_file->Is64Bit() ? elf_file->GetImpl64()->GetBaseAddress() :
2046 elf_file->GetImpl32()->GetBaseAddress();
2047 const uint8_t* oatdata = elf_file->FindDynamicSymbolAddress("oatdata");
2048 ASSERT_TRUE(oatdata != nullptr);
2049 ASSERT_TRUE(oatdata > base_address);
2050 // Note: We're assuming here that the virtual address offset is the same
2051 // as file offset. This is currently true for all oat files we generate.
2052 oatdata_offset = static_cast<size_t>(oatdata - base_address);
2053 const uint8_t* oatlastword = elf_file->FindDynamicSymbolAddress("oatlastword");
2054 ASSERT_TRUE(oatlastword != nullptr);
2055 ASSERT_TRUE(oatlastword > oatdata);
2056 oatdata_size = oatlastword - oatdata;
2057 }
2058
2059 // Check that we have the right `oatdata_offset`.
2060 int64_t length = file->GetLength();
2061 ASSERT_GE(length, static_cast<ssize_t>(oatdata_offset + sizeof(OatHeader)));
2062 alignas(OatHeader) uint8_t header_data[sizeof(OatHeader)];
2063 ASSERT_TRUE(file->PreadFully(header_data, sizeof(header_data), oatdata_offset));
2064 const OatHeader& header = reinterpret_cast<const OatHeader&>(header_data);
2065 ASSERT_TRUE(header.IsValid()) << header.GetValidationErrorMessage();
2066
2067 // Overwrite all oat data from version onwards with bytes with value 4.
2068 // (0x04040404 is not a valid version, we're using three decimal digits and '\0'.)
2069 //
2070 // We previously tried to find the value for key "debuggable" (bug 179221298)
2071 // in the key-value store before checking the oat header. This test tries to
2072 // ensure that such early processing of the key-value store shall crash.
2073 // Reading 0x04040404 as the size of the key-value store yields a bit over
2074 // 64MiB which should hopefully include some unmapped memory beyond the end
2075 // of the loaded oat file. Overwriting the whole embedded oat file ensures
2076 // that we do not match the key within the oat file but we could still
2077 // accidentally match it in the additional sections of the elf file, so this
2078 // approach could fail to catch similar issues. At the time of writing, this
2079 // test crashed when run without the fix on 64-bit host (but not 32-bit).
2080 static constexpr size_t kVersionOffset = sizeof(OatHeader::kOatMagic);
2081 static_assert(kVersionOffset < sizeof(OatHeader));
2082 std::vector<uint8_t> data(oatdata_size - kVersionOffset, 4u);
2083 ASSERT_TRUE(file->PwriteFully(data.data(), data.size(), oatdata_offset + kVersionOffset));
2084 UNUSED(oatdata_size);
2085 CHECK_EQ(file->FlushClose(), 0) << "Could not flush and close oat file";
2086 }
2087
2088 // Check that we reject the oat file without crashing.
2089 {
2090 std::string error_msg;
2091 std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
2092 base_oat_name,
2093 base_oat_name,
2094 /*executable=*/true,
2095 /*low_4gb=*/false,
2096 dex->GetLocation(),
2097 &error_msg));
2098 ASSERT_FALSE(odex_file != nullptr);
2099 }
2100 }
2101
2102 } // namespace art
2103