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