xref: /aosp_15_r20/art/dex2oat/dex2oat_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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