• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
18 #include <regex>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 
23 #include <sys/wait.h>
24 #include <unistd.h>
25 
26 #include <android-base/logging.h>
27 #include <android-base/macros.h>
28 #include <android-base/stringprintf.h>
29 
30 #include "common_runtime_test.h"
31 
32 #include "arch/instruction_set_features.h"
33 #include "base/macros.h"
34 #include "base/mutex-inl.h"
35 #include "base/string_view_cpp20.h"
36 #include "base/utils.h"
37 #include "base/zip_archive.h"
38 #include "dex/art_dex_file_loader.h"
39 #include "dex/base64_test_util.h"
40 #include "dex/bytecode_utils.h"
41 #include "dex/class_accessor-inl.h"
42 #include "dex/code_item_accessors-inl.h"
43 #include "dex/dex_file-inl.h"
44 #include "dex/dex_file_loader.h"
45 #include "dex2oat_environment_test.h"
46 #include "dex2oat_return_codes.h"
47 #include "elf_file.h"
48 #include "elf_file_impl.h"
49 #include "gc_root-inl.h"
50 #include "intern_table-inl.h"
51 #include "oat.h"
52 #include "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 static const char* kDisableCompactDex = "--compact-dex-level=none";
60 
61 using android::base::StringPrintf;
62 
63 class Dex2oatTest : public Dex2oatEnvironmentTest {
64  public:
TearDown()65   void TearDown() override {
66     Dex2oatEnvironmentTest::TearDown();
67 
68     output_ = "";
69     error_msg_ = "";
70   }
71 
72  protected:
GenerateOdexForTestWithStatus(const std::vector<std::string> & dex_locations,const std::string & odex_location,CompilerFilter::Filter filter,std::string * error_msg,const std::vector<std::string> & extra_args={},bool use_fd=false)73   int GenerateOdexForTestWithStatus(const std::vector<std::string>& dex_locations,
74                                     const std::string& odex_location,
75                                     CompilerFilter::Filter filter,
76                                     std::string* error_msg,
77                                     const std::vector<std::string>& extra_args = {},
78                                     bool use_fd = false) {
79     std::unique_ptr<File> oat_file;
80     std::vector<std::string> args;
81     // Add dex file args.
82     for (const std::string& dex_location : dex_locations) {
83       args.push_back("--dex-file=" + dex_location);
84     }
85     if (use_fd) {
86       oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
87       CHECK(oat_file != nullptr) << odex_location;
88       args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
89       args.push_back("--oat-location=" + odex_location);
90     } else {
91       args.push_back("--oat-file=" + odex_location);
92     }
93     args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
94     args.push_back("--runtime-arg");
95     args.push_back("-Xnorelocate");
96 
97     // Unless otherwise stated, use a small amount of threads, so that potential aborts are
98     // shorter. This can be overridden with extra_args.
99     args.push_back("-j4");
100 
101     args.insert(args.end(), extra_args.begin(), extra_args.end());
102 
103     int status = Dex2Oat(args, &output_, error_msg);
104     if (oat_file != nullptr) {
105       CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
106     }
107     return status;
108   }
109 
GenerateOdexForTest(const std::string & dex_location,const std::string & odex_location,CompilerFilter::Filter filter,const std::vector<std::string> & extra_args={},bool expect_success=true,bool use_fd=false,bool use_zip_fd=false)110   ::testing::AssertionResult GenerateOdexForTest(
111       const std::string& dex_location,
112       const std::string& odex_location,
113       CompilerFilter::Filter filter,
114       const std::vector<std::string>& extra_args = {},
115       bool expect_success = true,
116       bool use_fd = false,
117       bool use_zip_fd = false) WARN_UNUSED {
118     return GenerateOdexForTest(dex_location,
119                                odex_location,
120                                filter,
121                                extra_args,
122                                expect_success,
123                                use_fd,
124                                use_zip_fd,
__anon846a92100102(const OatFile&) 125                                [](const OatFile&) {});
126   }
127 
128   bool test_accepts_odex_file_on_failure = false;
129 
130   template <typename T>
GenerateOdexForTest(const std::string & dex_location,const std::string & odex_location,CompilerFilter::Filter filter,const std::vector<std::string> & extra_args,bool expect_success,bool use_fd,bool use_zip_fd,T check_oat)131   ::testing::AssertionResult GenerateOdexForTest(
132       const std::string& dex_location,
133       const std::string& odex_location,
134       CompilerFilter::Filter filter,
135       const std::vector<std::string>& extra_args,
136       bool expect_success,
137       bool use_fd,
138       bool use_zip_fd,
139       T check_oat) WARN_UNUSED {
140     std::vector<std::string> dex_locations;
141     if (use_zip_fd) {
142       std::string loc_arg = "--zip-location=" + dex_location;
143       CHECK(std::any_of(extra_args.begin(),
144                         extra_args.end(),
145                         [&](const std::string& s) { return s == loc_arg; }));
146       CHECK(std::any_of(extra_args.begin(),
147                         extra_args.end(),
148                         [](const std::string& s) { return StartsWith(s, "--zip-fd="); }));
149     } else {
150       dex_locations.push_back(dex_location);
151     }
152     std::string error_msg;
153     int status = GenerateOdexForTestWithStatus(dex_locations,
154                                                odex_location,
155                                                filter,
156                                                &error_msg,
157                                                extra_args,
158                                                use_fd);
159     bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
160     if (expect_success) {
161       if (!success) {
162         return ::testing::AssertionFailure()
163             << "Failed to compile odex: " << error_msg << std::endl << output_;
164       }
165 
166       // Verify the odex file was generated as expected.
167       std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
168                                                        odex_location.c_str(),
169                                                        odex_location.c_str(),
170                                                        /*executable=*/ false,
171                                                        /*low_4gb=*/ false,
172                                                        dex_location,
173                                                        &error_msg));
174       if (odex_file == nullptr) {
175         return ::testing::AssertionFailure() << "Could not open odex file: " << error_msg;
176       }
177 
178       CheckFilter(filter, odex_file->GetCompilerFilter());
179       check_oat(*(odex_file.get()));
180     } else {
181       if (success) {
182         return ::testing::AssertionFailure() << "Succeeded to compile odex: " << output_;
183       }
184 
185       error_msg_ = error_msg;
186 
187       if (!test_accepts_odex_file_on_failure) {
188         // Verify there's no loadable odex file.
189         std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
190                                                          odex_location.c_str(),
191                                                          odex_location.c_str(),
192                                                          /*executable=*/ false,
193                                                          /*low_4gb=*/ false,
194                                                          dex_location,
195                                                          &error_msg));
196         if (odex_file != nullptr) {
197           return ::testing::AssertionFailure() << "Could open odex file: " << error_msg;
198         }
199       }
200     }
201     return ::testing::AssertionSuccess();
202   }
203 
204   // Check the input compiler filter against the generated oat file's filter. May be overridden
205   // in subclasses when equality is not expected.
CheckFilter(CompilerFilter::Filter expected,CompilerFilter::Filter actual)206   virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
207     EXPECT_EQ(expected, actual);
208   }
209 
210   std::string output_ = "";
211   std::string error_msg_ = "";
212 };
213 
214 class Dex2oatSwapTest : public Dex2oatTest {
215  protected:
RunTest(bool use_fd,bool expect_use,const std::vector<std::string> & extra_args={})216   void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
217     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
218     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
219 
220     Copy(GetTestDexFileName(), dex_location);
221 
222     std::vector<std::string> copy(extra_args);
223 
224     std::unique_ptr<ScratchFile> sf;
225     if (use_fd) {
226       sf.reset(new ScratchFile());
227       copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
228     } else {
229       std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
230       copy.push_back("--swap-file=" + swap_location);
231     }
232     ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy));
233 
234     CheckValidity();
235     CheckResult(expect_use);
236   }
237 
GetTestDexFileName()238   virtual std::string GetTestDexFileName() {
239     return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps");
240   }
241 
CheckResult(bool expect_use)242   virtual void CheckResult(bool expect_use) {
243     if (kIsTargetBuild) {
244       CheckTargetResult(expect_use);
245     } else {
246       CheckHostResult(expect_use);
247     }
248   }
249 
CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED)250   virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
251     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
252     //       something for variants with file descriptor where we can control the lifetime of
253     //       the swap file and thus take a look at it.
254   }
255 
CheckHostResult(bool expect_use)256   virtual void CheckHostResult(bool expect_use) {
257     if (!kIsTargetBuild) {
258       if (expect_use) {
259         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
260             << output_;
261       } else {
262         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
263             << output_;
264       }
265     }
266   }
267 
268   // Check whether the dex2oat run was really successful.
CheckValidity()269   virtual void CheckValidity() {
270     if (kIsTargetBuild) {
271       CheckTargetValidity();
272     } else {
273       CheckHostValidity();
274     }
275   }
276 
CheckTargetValidity()277   virtual void CheckTargetValidity() {
278     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
279     //       something for variants with file descriptor where we can control the lifetime of
280     //       the swap file and thus take a look at it.
281   }
282 
283   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()284   virtual void CheckHostValidity() {
285     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
286   }
287 };
288 
TEST_F(Dex2oatSwapTest,DoNotUseSwapDefaultSingleSmall)289 TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
290   RunTest(/*use_fd=*/ false, /*expect_use=*/ false);
291   RunTest(/*use_fd=*/ true, /*expect_use=*/ false);
292 }
293 
TEST_F(Dex2oatSwapTest,DoNotUseSwapSingle)294 TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
295   RunTest(/*use_fd=*/ false, /*expect_use=*/ false, { "--swap-dex-size-threshold=0" });
296   RunTest(/*use_fd=*/ true, /*expect_use=*/ false, { "--swap-dex-size-threshold=0" });
297 }
298 
TEST_F(Dex2oatSwapTest,DoNotUseSwapSmall)299 TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
300   RunTest(/*use_fd=*/ false, /*expect_use=*/ false, { "--swap-dex-count-threshold=0" });
301   RunTest(/*use_fd=*/ true, /*expect_use=*/ false, { "--swap-dex-count-threshold=0" });
302 }
303 
TEST_F(Dex2oatSwapTest,DoUseSwapSingleSmall)304 TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
305   RunTest(/*use_fd=*/ false,
306           /*expect_use=*/ true,
307           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
308   RunTest(/*use_fd=*/ true,
309           /*expect_use=*/ true,
310           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
311 }
312 
313 class Dex2oatSwapUseTest : public Dex2oatSwapTest {
314  protected:
CheckHostResult(bool expect_use)315   void CheckHostResult(bool expect_use) override {
316     if (!kIsTargetBuild) {
317       if (expect_use) {
318         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
319             << output_;
320       } else {
321         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
322             << output_;
323       }
324     }
325   }
326 
GetTestDexFileName()327   std::string GetTestDexFileName() override {
328     // Use Statics as it has a handful of functions.
329     return CommonRuntimeTest::GetTestDexFileName("Statics");
330   }
331 
GrabResult1()332   void GrabResult1() {
333     if (!kIsTargetBuild) {
334       native_alloc_1_ = ParseNativeAlloc();
335       swap_1_ = ParseSwap(/*expected=*/ false);
336     } else {
337       native_alloc_1_ = std::numeric_limits<size_t>::max();
338       swap_1_ = 0;
339     }
340   }
341 
GrabResult2()342   void GrabResult2() {
343     if (!kIsTargetBuild) {
344       native_alloc_2_ = ParseNativeAlloc();
345       swap_2_ = ParseSwap(/*expected=*/ true);
346     } else {
347       native_alloc_2_ = 0;
348       swap_2_ = std::numeric_limits<size_t>::max();
349     }
350   }
351 
352  private:
ParseNativeAlloc()353   size_t ParseNativeAlloc() {
354     std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)");
355     std::smatch native_alloc_match;
356     bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex);
357     if (!found) {
358       EXPECT_TRUE(found);
359       return 0;
360     }
361     if (native_alloc_match.size() != 2U) {
362       EXPECT_EQ(native_alloc_match.size(), 2U);
363       return 0;
364     }
365 
366     std::istringstream stream(native_alloc_match[1].str());
367     size_t value;
368     stream >> value;
369 
370     return value;
371   }
372 
ParseSwap(bool expected)373   size_t ParseSwap(bool expected) {
374     std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)");
375     std::smatch swap_match;
376     bool found = std::regex_search(output_, swap_match, swap_regex);
377     if (found != expected) {
378       EXPECT_EQ(expected, found);
379       return 0;
380     }
381 
382     if (!found) {
383       return 0;
384     }
385 
386     if (swap_match.size() != 2U) {
387       EXPECT_EQ(swap_match.size(), 2U);
388       return 0;
389     }
390 
391     std::istringstream stream(swap_match[1].str());
392     size_t value;
393     stream >> value;
394 
395     return value;
396   }
397 
398  protected:
399   size_t native_alloc_1_;
400   size_t native_alloc_2_;
401 
402   size_t swap_1_;
403   size_t swap_2_;
404 };
405 
TEST_F(Dex2oatSwapUseTest,CheckSwapUsage)406 TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
407   // Native memory usage isn't correctly tracked when running under ASan.
408   TEST_DISABLED_FOR_MEMORY_TOOL();
409 
410   // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
411   // hold true on some x86 or x86_64 systems; disable this test while we
412   // investigate (b/29259363).
413   TEST_DISABLED_FOR_X86();
414   TEST_DISABLED_FOR_X86_64();
415 
416   RunTest(/*use_fd=*/ false,
417           /*expect_use=*/ false);
418   GrabResult1();
419   std::string output_1 = output_;
420 
421   output_ = "";
422 
423   RunTest(/*use_fd=*/ false,
424           /*expect_use=*/ true,
425           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
426   GrabResult2();
427   std::string output_2 = output_;
428 
429   if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) {
430     EXPECT_LT(native_alloc_2_, native_alloc_1_);
431     EXPECT_LT(swap_1_, swap_2_);
432 
433     LOG(ERROR) << output_1;
434     LOG(ERROR) << output_2;
435   }
436 }
437 
438 class Dex2oatVeryLargeTest : public Dex2oatTest {
439  protected:
CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,CompilerFilter::Filter result ATTRIBUTE_UNUSED)440   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
441                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) override {
442     // Ignore, we'll do our own checks.
443   }
444 
RunTest(CompilerFilter::Filter filter,bool expect_large,bool expect_downgrade,const std::vector<std::string> & extra_args={})445   void RunTest(CompilerFilter::Filter filter,
446                bool expect_large,
447                bool expect_downgrade,
448                const std::vector<std::string>& extra_args = {}) {
449     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
450     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
451     std::string app_image_file = GetScratchDir() + "/Test.art";
452 
453     Copy(GetDexSrc1(), dex_location);
454 
455     std::vector<std::string> new_args(extra_args);
456     new_args.push_back("--app-image-file=" + app_image_file);
457     ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, filter, new_args));
458 
459     CheckValidity();
460     CheckResult(dex_location,
461                 odex_location,
462                 app_image_file,
463                 filter,
464                 expect_large,
465                 expect_downgrade);
466   }
467 
CheckResult(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file,CompilerFilter::Filter filter,bool expect_large,bool expect_downgrade)468   void CheckResult(const std::string& dex_location,
469                    const std::string& odex_location,
470                    const std::string& app_image_file,
471                    CompilerFilter::Filter filter,
472                    bool expect_large,
473                    bool expect_downgrade) {
474     if (expect_downgrade) {
475       EXPECT_TRUE(expect_large);
476     }
477     // Host/target independent checks.
478     std::string error_msg;
479     std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
480                                                      odex_location.c_str(),
481                                                      odex_location.c_str(),
482                                                      /*executable=*/ false,
483                                                      /*low_4gb=*/ false,
484                                                      dex_location,
485                                                      &error_msg));
486     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
487     EXPECT_GT(app_image_file.length(), 0u);
488     std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file.c_str()));
489     if (expect_large) {
490       // Note: we cannot check the following
491       // EXPECT_FALSE(CompilerFilter::IsAotCompilationEnabled(odex_file->GetCompilerFilter()));
492       // The reason is that the filter override currently happens when the dex files are
493       // loaded in dex2oat, which is after the oat file has been started. Thus, the header
494       // store cannot be changed, and the original filter is set in stone.
495 
496       for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
497         std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
498         ASSERT_TRUE(dex_file != nullptr);
499         uint32_t class_def_count = dex_file->NumClassDefs();
500         ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
501         for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
502           OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
503           EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
504         }
505       }
506 
507       // If the input filter was "below," it should have been used.
508       if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract, filter)) {
509         EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
510       }
511 
512       // If expect large, make sure the app image isn't generated or is empty.
513       if (file != nullptr) {
514         EXPECT_EQ(file->GetLength(), 0u);
515       }
516     } else {
517       EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
518       ASSERT_TRUE(file != nullptr) << app_image_file;
519       EXPECT_GT(file->GetLength(), 0u);
520     }
521 
522     // Host/target dependent checks.
523     if (kIsTargetBuild) {
524       CheckTargetResult(expect_downgrade);
525     } else {
526       CheckHostResult(expect_downgrade);
527     }
528   }
529 
CheckTargetResult(bool expect_downgrade ATTRIBUTE_UNUSED)530   void CheckTargetResult(bool expect_downgrade ATTRIBUTE_UNUSED) {
531     // TODO: Ignore for now. May do something for fd things.
532   }
533 
CheckHostResult(bool expect_downgrade)534   void CheckHostResult(bool expect_downgrade) {
535     if (!kIsTargetBuild) {
536       if (expect_downgrade) {
537         EXPECT_NE(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
538       } else {
539         EXPECT_EQ(output_.find("Very large app, downgrading to"), std::string::npos) << output_;
540       }
541     }
542   }
543 
544   // Check whether the dex2oat run was really successful.
CheckValidity()545   void CheckValidity() {
546     if (kIsTargetBuild) {
547       CheckTargetValidity();
548     } else {
549       CheckHostValidity();
550     }
551   }
552 
CheckTargetValidity()553   void CheckTargetValidity() {
554     // TODO: Ignore for now.
555   }
556 
557   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()558   void CheckHostValidity() {
559     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
560   }
561 };
562 
TEST_F(Dex2oatVeryLargeTest,DontUseVeryLarge)563 TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
564   RunTest(CompilerFilter::kAssumeVerified, false, false);
565   RunTest(CompilerFilter::kExtract, false, false);
566   RunTest(CompilerFilter::kQuicken, false, false);
567   RunTest(CompilerFilter::kSpeed, false, false);
568 
569   RunTest(CompilerFilter::kAssumeVerified, false, false, { "--very-large-app-threshold=10000000" });
570   RunTest(CompilerFilter::kExtract, false, false, { "--very-large-app-threshold=10000000" });
571   RunTest(CompilerFilter::kQuicken, false, false, { "--very-large-app-threshold=10000000" });
572   RunTest(CompilerFilter::kSpeed, false, false, { "--very-large-app-threshold=10000000" });
573 }
574 
TEST_F(Dex2oatVeryLargeTest,UseVeryLarge)575 TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
576   RunTest(CompilerFilter::kAssumeVerified, true, false, { "--very-large-app-threshold=100" });
577   RunTest(CompilerFilter::kExtract, true, false, { "--very-large-app-threshold=100" });
578   RunTest(CompilerFilter::kQuicken, true, true, { "--very-large-app-threshold=100" });
579   RunTest(CompilerFilter::kSpeed, true, true, { "--very-large-app-threshold=100" });
580 }
581 
582 // Regressin test for b/35665292.
TEST_F(Dex2oatVeryLargeTest,SpeedProfileNoProfile)583 TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) {
584   // Test that dex2oat doesn't crash with speed-profile but no input profile.
585   RunTest(CompilerFilter::kSpeedProfile, false, false);
586 }
587 
588 class Dex2oatLayoutTest : public Dex2oatTest {
589  protected:
CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,CompilerFilter::Filter result ATTRIBUTE_UNUSED)590   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
591                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) override {
592     // Ignore, we'll do our own checks.
593   }
594 
595   // Emits a profile with a single dex file with the given location and classes ranging
596   // from 0 to num_classes.
GenerateProfile(const std::string & test_profile,const DexFile * dex,size_t num_classes)597   void GenerateProfile(const std::string& test_profile,
598                        const DexFile* dex,
599                        size_t num_classes) {
600     int profile_test_fd = open(test_profile.c_str(),
601                                O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
602                                0644);
603     CHECK_GE(profile_test_fd, 0);
604 
605     ProfileCompilationInfo info;
606     std::vector<dex::TypeIndex> classes;;
607     for (size_t i = 0; i < num_classes; ++i) {
608       classes.push_back(dex::TypeIndex(1 + i));
609     }
610     info.AddClassesForDex(dex, classes.begin(), classes.end());
611     bool result = info.Save(profile_test_fd);
612     close(profile_test_fd);
613     ASSERT_TRUE(result);
614   }
615 
CompileProfileOdex(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file_name,bool use_fd,size_t num_profile_classes,const std::vector<std::string> & extra_args={},bool expect_success=true)616   void CompileProfileOdex(const std::string& dex_location,
617                           const std::string& odex_location,
618                           const std::string& app_image_file_name,
619                           bool use_fd,
620                           size_t num_profile_classes,
621                           const std::vector<std::string>& extra_args = {},
622                           bool expect_success = true) {
623     const std::string profile_location = GetScratchDir() + "/primary.prof";
624     const char* location = dex_location.c_str();
625     std::string error_msg;
626     std::vector<std::unique_ptr<const DexFile>> dex_files;
627     const ArtDexFileLoader dex_file_loader;
628     ASSERT_TRUE(dex_file_loader.Open(
629         location, location, /*verify=*/ true, /*verify_checksum=*/ true, &error_msg, &dex_files));
630     EXPECT_EQ(dex_files.size(), 1U);
631     std::unique_ptr<const DexFile>& dex_file = dex_files[0];
632     GenerateProfile(profile_location, dex_file.get(), num_profile_classes);
633     std::vector<std::string> copy(extra_args);
634     copy.push_back("--profile-file=" + profile_location);
635     std::unique_ptr<File> app_image_file;
636     if (!app_image_file_name.empty()) {
637       if (use_fd) {
638         app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str()));
639         copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd()));
640       } else {
641         copy.push_back("--app-image-file=" + app_image_file_name);
642       }
643     }
644     ASSERT_TRUE(GenerateOdexForTest(dex_location,
645                                     odex_location,
646                                     CompilerFilter::kSpeedProfile,
647                                     copy,
648                                     expect_success,
649                                     use_fd));
650     if (app_image_file != nullptr) {
651       ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
652     }
653   }
654 
GetImageObjectSectionSize(const std::string & image_file_name)655   uint64_t GetImageObjectSectionSize(const std::string& image_file_name) {
656     EXPECT_FALSE(image_file_name.empty());
657     std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
658     CHECK(file != nullptr);
659     ImageHeader image_header;
660     const bool success = file->ReadFully(&image_header, sizeof(image_header));
661     CHECK(success);
662     CHECK(image_header.IsValid());
663     ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
664     return image_header.GetObjectsSection().Size();
665   }
666 
RunTest(bool app_image)667   void RunTest(bool app_image) {
668     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
669     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
670     std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): "";
671     Copy(GetDexSrc2(), dex_location);
672 
673     uint64_t image_file_empty_profile = 0;
674     if (app_image) {
675       CompileProfileOdex(dex_location,
676                          odex_location,
677                          app_image_file,
678                          /*use_fd=*/ false,
679                          /*num_profile_classes=*/ 0);
680       CheckValidity();
681       // Don't check the result since CheckResult relies on the class being in the profile.
682       image_file_empty_profile = GetImageObjectSectionSize(app_image_file);
683       EXPECT_GT(image_file_empty_profile, 0u);
684     }
685 
686     // Small profile.
687     CompileProfileOdex(dex_location,
688                        odex_location,
689                        app_image_file,
690                        /*use_fd=*/ false,
691                        /*num_profile_classes=*/ 1);
692     CheckValidity();
693     CheckResult(dex_location, odex_location, app_image_file);
694 
695     if (app_image) {
696       // Test that the profile made a difference by adding more classes.
697       const uint64_t image_file_small_profile = GetImageObjectSectionSize(app_image_file);
698       ASSERT_LT(image_file_empty_profile, image_file_small_profile);
699     }
700   }
701 
RunTestVDex()702   void RunTestVDex() {
703     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
704     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
705     std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
706     std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art";
707     Copy(GetDexSrc2(), dex_location);
708 
709     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
710     CHECK(vdex_file1 != nullptr) << vdex_location;
711     ScratchFile vdex_file2;
712     {
713       std::string input_vdex = "--input-vdex-fd=-1";
714       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
715       CompileProfileOdex(dex_location,
716                          odex_location,
717                          app_image_file_name,
718                          /*use_fd=*/ true,
719                          /*num_profile_classes=*/ 1,
720                          { input_vdex, output_vdex });
721       EXPECT_GT(vdex_file1->GetLength(), 0u);
722     }
723     {
724       // Test that vdex and dexlayout fail gracefully.
725       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
726       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
727       CompileProfileOdex(dex_location,
728                          odex_location,
729                          app_image_file_name,
730                          /*use_fd=*/ true,
731                          /*num_profile_classes=*/ 1,
732                          { input_vdex, output_vdex },
733                          /*expect_success=*/ true);
734       EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
735     }
736     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
737     CheckValidity();
738   }
739 
CheckResult(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file_name)740   void CheckResult(const std::string& dex_location,
741                    const std::string& odex_location,
742                    const std::string& app_image_file_name) {
743     // Host/target independent checks.
744     std::string error_msg;
745     std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
746                                                      odex_location.c_str(),
747                                                      odex_location.c_str(),
748                                                      /*executable=*/ false,
749                                                      /*low_4gb=*/ false,
750                                                      dex_location,
751                                                      &error_msg));
752     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
753 
754     const char* location = dex_location.c_str();
755     std::vector<std::unique_ptr<const DexFile>> dex_files;
756     const ArtDexFileLoader dex_file_loader;
757     ASSERT_TRUE(dex_file_loader.Open(
758         location, location, /*verify=*/ true, /*verify_checksum=*/ true, &error_msg, &dex_files));
759     EXPECT_EQ(dex_files.size(), 1U);
760     std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
761 
762     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
763       std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
764       ASSERT_TRUE(new_dex_file != nullptr);
765       uint32_t class_def_count = new_dex_file->NumClassDefs();
766       ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
767       ASSERT_GE(class_def_count, 2U);
768 
769       // Make sure the indexes stay the same.
770       std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
771       std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
772       std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
773       std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
774       EXPECT_EQ(old_class0, new_class0);
775       EXPECT_EQ(old_class1, new_class1);
776     }
777 
778     EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
779 
780     if (!app_image_file_name.empty()) {
781       // Go peek at the image header to make sure it was large enough to contain the class.
782       std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str()));
783       ImageHeader image_header;
784       bool success = file->ReadFully(&image_header, sizeof(image_header));
785       ASSERT_TRUE(success);
786       ASSERT_TRUE(image_header.IsValid());
787       EXPECT_GT(image_header.GetObjectsSection().Size(), 0u);
788     }
789   }
790 
791   // Check whether the dex2oat run was really successful.
CheckValidity()792   void CheckValidity() {
793     if (kIsTargetBuild) {
794       CheckTargetValidity();
795     } else {
796       CheckHostValidity();
797     }
798   }
799 
CheckTargetValidity()800   void CheckTargetValidity() {
801     // TODO: Ignore for now.
802   }
803 
804   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()805   void CheckHostValidity() {
806     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
807   }
808 };
809 
TEST_F(Dex2oatLayoutTest,TestLayout)810 TEST_F(Dex2oatLayoutTest, TestLayout) {
811   RunTest(/*app_image=*/ false);
812 }
813 
TEST_F(Dex2oatLayoutTest,TestLayoutAppImage)814 TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) {
815   RunTest(/*app_image=*/ true);
816 }
817 
TEST_F(Dex2oatLayoutTest,TestVdexLayout)818 TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
819   RunTestVDex();
820 }
821 
822 class Dex2oatUnquickenTest : public Dex2oatTest {
823  protected:
RunUnquickenMultiDex()824   void RunUnquickenMultiDex() {
825     std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar";
826     std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex";
827     std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex";
828     Copy(GetTestDexFileName("MultiDex"), dex_location);
829 
830     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
831     CHECK(vdex_file1 != nullptr) << vdex_location;
832     // Quicken the dex file into a vdex file.
833     {
834       std::string input_vdex = "--input-vdex-fd=-1";
835       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
836       ASSERT_TRUE(GenerateOdexForTest(dex_location,
837                                       odex_location,
838                                       CompilerFilter::kQuicken,
839                                       { input_vdex, output_vdex },
840                                       /* expect_success= */ true,
841                                       /* use_fd= */ true));
842       EXPECT_GT(vdex_file1->GetLength(), 0u);
843     }
844     // Get the dex file checksums.
845     std::vector<uint32_t> checksums1;
846     GetDexFileChecksums(dex_location, odex_location, &checksums1);
847     // Unquicken by running the verify compiler filter on the vdex file.
848     {
849       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
850       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
851       ASSERT_TRUE(GenerateOdexForTest(dex_location,
852                                       odex_location,
853                                       CompilerFilter::kVerify,
854                                       { input_vdex, output_vdex, kDisableCompactDex },
855                                       /* expect_success= */ true,
856                                       /* use_fd= */ true));
857     }
858     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
859     CheckResult(dex_location, odex_location);
860     // Verify that the checksums did not change.
861     std::vector<uint32_t> checksums2;
862     GetDexFileChecksums(dex_location, odex_location, &checksums2);
863     ASSERT_EQ(checksums1.size(), checksums2.size());
864     for (size_t i = 0; i != checksums1.size(); ++i) {
865       EXPECT_EQ(checksums1[i], checksums2[i]) << i;
866     }
867   }
868 
RunUnquickenMultiDexCDex()869   void RunUnquickenMultiDexCDex() {
870     std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar";
871     std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex";
872     std::string odex_location2 = GetOdexDir() + "/UnquickenMultiDex2.odex";
873     std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex";
874     std::string vdex_location2 = GetOdexDir() + "/UnquickenMultiDex2.vdex";
875     Copy(GetTestDexFileName("MultiDex"), dex_location);
876 
877     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
878     std::unique_ptr<File> vdex_file2(OS::CreateEmptyFile(vdex_location2.c_str()));
879     CHECK(vdex_file1 != nullptr) << vdex_location;
880     CHECK(vdex_file2 != nullptr) << vdex_location2;
881 
882     // Quicken the dex file into a vdex file.
883     {
884       std::string input_vdex = "--input-vdex-fd=-1";
885       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
886       ASSERT_TRUE(GenerateOdexForTest(dex_location,
887                                       odex_location,
888                                       CompilerFilter::kQuicken,
889                                       { input_vdex, output_vdex, "--compact-dex-level=fast"},
890                                       /* expect_success= */ true,
891                                       /* use_fd= */ true));
892       EXPECT_GT(vdex_file1->GetLength(), 0u);
893     }
894     // Unquicken by running the verify compiler filter on the vdex file.
895     {
896       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
897       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2->Fd());
898       ASSERT_TRUE(GenerateOdexForTest(dex_location,
899                                       odex_location2,
900                                       CompilerFilter::kVerify,
901                                       { input_vdex, output_vdex, "--compact-dex-level=none"},
902                                       /* expect_success= */ true,
903                                       /* use_fd= */ true));
904     }
905     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
906     ASSERT_EQ(vdex_file2->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
907     CheckResult(dex_location, odex_location2);
908   }
909 
CheckResult(const std::string & dex_location,const std::string & odex_location)910   void CheckResult(const std::string& dex_location, const std::string& odex_location) {
911     std::string error_msg;
912     std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
913                                                      odex_location.c_str(),
914                                                      odex_location.c_str(),
915                                                      /*executable=*/ false,
916                                                      /*low_4gb=*/ false,
917                                                      dex_location,
918                                                      &error_msg));
919     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
920     ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u);
921 
922     // Iterate over the dex files and ensure there is no quickened instruction.
923     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
924       std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
925       for (ClassAccessor accessor : dex_file->GetClasses()) {
926         for (const ClassAccessor::Method& method : accessor.GetMethods()) {
927           for (const DexInstructionPcPair& inst : method.GetInstructions()) {
928             ASSERT_FALSE(inst->IsQuickened()) << inst->Opcode() << " " << output_;
929           }
930         }
931       }
932     }
933   }
934 
GetDexFileChecksums(const std::string & dex_location,const std::string & odex_location,std::vector<uint32_t> * checksums)935   void GetDexFileChecksums(const std::string& dex_location,
936                            const std::string& odex_location,
937                            /*out*/std::vector<uint32_t>* checksums) {
938     std::string error_msg;
939     std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
940                                                      odex_location.c_str(),
941                                                      odex_location.c_str(),
942                                                      /*executable=*/ false,
943                                                      /*low_4gb=*/ false,
944                                                      dex_location,
945                                                      &error_msg));
946     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
947     ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u);
948     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
949       checksums->push_back(oat_dex_file->GetDexFileLocationChecksum());
950     }
951   }
952 };
953 
TEST_F(Dex2oatUnquickenTest,UnquickenMultiDex)954 TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) {
955   RunUnquickenMultiDex();
956 }
957 
TEST_F(Dex2oatUnquickenTest,UnquickenMultiDexCDex)958 TEST_F(Dex2oatUnquickenTest, UnquickenMultiDexCDex) {
959   RunUnquickenMultiDexCDex();
960 }
961 
962 class Dex2oatWatchdogTest : public Dex2oatTest {
963  protected:
RunTest(bool expect_success,const std::vector<std::string> & extra_args={})964   void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {
965     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
966     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
967 
968     Copy(GetTestDexFileName(), dex_location);
969 
970     std::vector<std::string> copy(extra_args);
971 
972     std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
973     copy.push_back("--swap-file=" + swap_location);
974     copy.push_back("-j512");  // Excessive idle threads just slow down dex2oat.
975     ASSERT_TRUE(GenerateOdexForTest(dex_location,
976                                     odex_location,
977                                     CompilerFilter::kSpeed,
978                                     copy,
979                                     expect_success));
980   }
981 
GetTestDexFileName()982   std::string GetTestDexFileName() {
983     return GetDexSrc1();
984   }
985 };
986 
TEST_F(Dex2oatWatchdogTest,TestWatchdogOK)987 TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
988   // Check with default.
989   RunTest(true);
990 
991   // Check with ten minutes.
992   RunTest(true, { "--watchdog-timeout=600000" });
993 }
994 
TEST_F(Dex2oatWatchdogTest,TestWatchdogTrigger)995 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
996   // This test is frequently interrupted by signal_dumper on host (x86);
997   // disable it while we investigate (b/121352534).
998   TEST_DISABLED_FOR_X86();
999 
1000   // The watchdog is independent of dex2oat and will not delete intermediates. It is possible
1001   // that the compilation succeeds and the file is completely written by the time the watchdog
1002   // kills dex2oat (but the dex2oat threads must have been scheduled pretty badly).
1003   test_accepts_odex_file_on_failure = true;
1004 
1005   // Check with ten milliseconds.
1006   RunTest(false, { "--watchdog-timeout=10" });
1007 }
1008 
1009 class Dex2oatReturnCodeTest : public Dex2oatTest {
1010  protected:
RunTest(const std::vector<std::string> & extra_args={})1011   int RunTest(const std::vector<std::string>& extra_args = {}) {
1012     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
1013     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
1014 
1015     Copy(GetTestDexFileName(), dex_location);
1016 
1017     std::string error_msg;
1018     return GenerateOdexForTestWithStatus({dex_location},
1019                                          odex_location,
1020                                          CompilerFilter::kSpeed,
1021                                          &error_msg,
1022                                          extra_args);
1023   }
1024 
GetTestDexFileName()1025   std::string GetTestDexFileName() {
1026     return GetDexSrc1();
1027   }
1028 };
1029 
TEST_F(Dex2oatReturnCodeTest,TestCreateRuntime)1030 TEST_F(Dex2oatReturnCodeTest, TestCreateRuntime) {
1031   TEST_DISABLED_FOR_MEMORY_TOOL();  // b/19100793
1032   int status = RunTest({ "--boot-image=/this/does/not/exist/yolo.oat" });
1033   EXPECT_EQ(static_cast<int>(dex2oat::ReturnCode::kCreateRuntime), WEXITSTATUS(status)) << output_;
1034 }
1035 
1036 class Dex2oatClassLoaderContextTest : public Dex2oatTest {
1037  protected:
RunTest(const char * class_loader_context,const char * expected_classpath_key,bool expected_success,bool use_second_source=false,bool generate_image=false)1038   void RunTest(const char* class_loader_context,
1039                const char* expected_classpath_key,
1040                bool expected_success,
1041                bool use_second_source = false,
1042                bool generate_image = false) {
1043     std::string dex_location = GetUsedDexLocation();
1044     std::string odex_location = GetUsedOatLocation();
1045 
1046     Copy(use_second_source ? GetDexSrc2() : GetDexSrc1(), dex_location);
1047 
1048     std::string error_msg;
1049     std::vector<std::string> extra_args;
1050     if (class_loader_context != nullptr) {
1051       extra_args.push_back(std::string("--class-loader-context=") + class_loader_context);
1052     }
1053     if (generate_image) {
1054       extra_args.push_back(std::string("--app-image-file=") + GetUsedImageLocation());
1055     }
1056     auto check_oat = [expected_classpath_key](const OatFile& oat_file) {
1057       ASSERT_TRUE(expected_classpath_key != nullptr);
1058       const char* classpath = oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey);
1059       ASSERT_TRUE(classpath != nullptr);
1060       ASSERT_STREQ(expected_classpath_key, classpath);
1061     };
1062 
1063     ASSERT_TRUE(GenerateOdexForTest(dex_location,
1064                                     odex_location,
1065                                     CompilerFilter::kQuicken,
1066                                     extra_args,
1067                                     expected_success,
1068                                     /*use_fd=*/ false,
1069                                     /*use_zip_fd=*/ false,
1070                                     check_oat));
1071   }
1072 
GetUsedDexLocation()1073   std::string GetUsedDexLocation() {
1074     return GetScratchDir() + "/Context.jar";
1075   }
1076 
GetUsedOatLocation()1077   std::string GetUsedOatLocation() {
1078     return GetOdexDir() + "/Context.odex";
1079   }
1080 
GetUsedImageLocation()1081   std::string GetUsedImageLocation() {
1082     return GetOdexDir() + "/Context.art";
1083   }
1084 
1085   const char* kEmptyClassPathKey = "PCL[]";
1086 };
1087 
TEST_F(Dex2oatClassLoaderContextTest,InvalidContext)1088 TEST_F(Dex2oatClassLoaderContextTest, InvalidContext) {
1089   RunTest("Invalid[]", /*expected_classpath_key*/ nullptr, /*expected_success*/ false);
1090 }
1091 
TEST_F(Dex2oatClassLoaderContextTest,EmptyContext)1092 TEST_F(Dex2oatClassLoaderContextTest, EmptyContext) {
1093   RunTest("PCL[]", kEmptyClassPathKey, /*expected_success*/ true);
1094 }
1095 
TEST_F(Dex2oatClassLoaderContextTest,SpecialContext)1096 TEST_F(Dex2oatClassLoaderContextTest, SpecialContext) {
1097   RunTest(OatFile::kSpecialSharedLibrary,
1098           OatFile::kSpecialSharedLibrary,
1099           /*expected_success*/ true);
1100 }
1101 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithTheSourceDexFiles)1102 TEST_F(Dex2oatClassLoaderContextTest, ContextWithTheSourceDexFiles) {
1103   std::string context = "PCL[" + GetUsedDexLocation() + "]";
1104   RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
1105 }
1106 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithOtherDexFiles)1107 TEST_F(Dex2oatClassLoaderContextTest, ContextWithOtherDexFiles) {
1108   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Nested");
1109 
1110   std::string context = "PCL[" + dex_files[0]->GetLocation() + "]";
1111   std::string expected_classpath_key = "PCL[" +
1112       dex_files[0]->GetLocation() + "*" + std::to_string(dex_files[0]->GetLocationChecksum()) + "]";
1113   RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1114 }
1115 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithStrippedDexFiles)1116 TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFiles) {
1117   std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar";
1118   Copy(GetStrippedDexSrc1(), stripped_classpath);
1119 
1120   std::string context = "PCL[" + stripped_classpath + "]";
1121   // Expect an empty context because stripped dex files cannot be open.
1122   RunTest(context.c_str(), kEmptyClassPathKey , /*expected_success*/ true);
1123 }
1124 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithStrippedDexFilesBackedByOdex)1125 TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFilesBackedByOdex) {
1126   std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar";
1127   std::string odex_for_classpath = GetOdexDir() + "/stripped_classpath.odex";
1128 
1129   Copy(GetDexSrc1(), stripped_classpath);
1130 
1131   ASSERT_TRUE(GenerateOdexForTest(stripped_classpath,
1132                                   odex_for_classpath,
1133                                   CompilerFilter::kQuicken,
1134                                   {},
1135                                   true));
1136 
1137   // Strip the dex file
1138   Copy(GetStrippedDexSrc1(), stripped_classpath);
1139 
1140   std::string context = "PCL[" + stripped_classpath + "]";
1141   std::string expected_classpath_key;
1142   {
1143     // Open the oat file to get the expected classpath.
1144     OatFileAssistant oat_file_assistant(stripped_classpath.c_str(), kRuntimeISA, false, false);
1145     std::unique_ptr<OatFile> oat_file(oat_file_assistant.GetBestOatFile());
1146     std::vector<std::unique_ptr<const DexFile>> oat_dex_files =
1147         OatFileAssistant::LoadDexFiles(*oat_file, stripped_classpath.c_str());
1148     expected_classpath_key = "PCL[";
1149     for (size_t i = 0; i < oat_dex_files.size(); i++) {
1150       if (i > 0) {
1151         expected_classpath_key + ":";
1152       }
1153       expected_classpath_key += oat_dex_files[i]->GetLocation() + "*" +
1154           std::to_string(oat_dex_files[i]->GetLocationChecksum());
1155     }
1156     expected_classpath_key += "]";
1157   }
1158 
1159   RunTest(context.c_str(),
1160           expected_classpath_key.c_str(),
1161           /*expected_success*/ true,
1162           /*use_second_source*/ true);
1163 }
1164 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithNotExistentDexFiles)1165 TEST_F(Dex2oatClassLoaderContextTest, ContextWithNotExistentDexFiles) {
1166   std::string context = "PCL[does_not_exists.dex]";
1167   // Expect an empty context because stripped dex files cannot be open.
1168   RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true);
1169 }
1170 
TEST_F(Dex2oatClassLoaderContextTest,ChainContext)1171 TEST_F(Dex2oatClassLoaderContextTest, ChainContext) {
1172   std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1173   std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1174 
1175   std::string context = "PCL[" + GetTestDexFileName("Nested") + "];" +
1176       "DLC[" + GetTestDexFileName("MultiDex") + "]";
1177   std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "];" +
1178       "DLC[" + CreateClassPathWithChecksums(dex_files2) + "]";
1179 
1180   RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1181 }
1182 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSharedLibrary)1183 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibrary) {
1184   std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1185   std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1186 
1187   std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" +
1188       "{PCL[" + GetTestDexFileName("MultiDex") + "]}";
1189   std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1190       "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}";
1191   RunTest(context.c_str(), expected_classpath_key.c_str(), true);
1192 }
1193 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSharedLibraryAndImage)1194 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibraryAndImage) {
1195   std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1196   std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1197 
1198   std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" +
1199       "{PCL[" + GetTestDexFileName("MultiDex") + "]}";
1200   std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1201       "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}";
1202   RunTest(context.c_str(),
1203           expected_classpath_key.c_str(),
1204           /*expected_success=*/ true,
1205           /*use_second_source=*/ false,
1206           /*generate_image=*/ true);
1207 }
1208 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSameSharedLibrariesAndImage)1209 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSameSharedLibrariesAndImage) {
1210   std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1211   std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1212 
1213   std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" +
1214       "{PCL[" + GetTestDexFileName("MultiDex") + "]" +
1215       "#PCL[" + GetTestDexFileName("MultiDex") + "]}";
1216   std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1217       "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]" +
1218       "#PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}";
1219   RunTest(context.c_str(),
1220           expected_classpath_key.c_str(),
1221           /*expected_success=*/ true,
1222           /*use_second_source=*/ false,
1223           /*generate_image=*/ true);
1224 }
1225 
TEST_F(Dex2oatClassLoaderContextTest,ContextWithSharedLibrariesDependenciesAndImage)1226 TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibrariesDependenciesAndImage) {
1227   std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested");
1228   std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
1229 
1230   std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" +
1231       "{PCL[" + GetTestDexFileName("MultiDex") + "]" +
1232       "{PCL[" + GetTestDexFileName("Nested") + "]}}";
1233   std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" +
1234       "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]" +
1235       "{PCL[" + CreateClassPathWithChecksums(dex_files1) + "]}}";
1236   RunTest(context.c_str(),
1237           expected_classpath_key.c_str(),
1238           /*expected_success=*/ true,
1239           /*use_second_source=*/ false,
1240           /*generate_image=*/ true);
1241 }
1242 
1243 class Dex2oatDeterminism : public Dex2oatTest {};
1244 
TEST_F(Dex2oatDeterminism,UnloadCompile)1245 TEST_F(Dex2oatDeterminism, UnloadCompile) {
1246   Runtime* const runtime = Runtime::Current();
1247   std::string out_dir = GetScratchDir();
1248   const std::string base_oat_name = out_dir + "/base.oat";
1249   const std::string base_vdex_name = out_dir + "/base.vdex";
1250   const std::string unload_oat_name = out_dir + "/unload.oat";
1251   const std::string unload_vdex_name = out_dir + "/unload.vdex";
1252   const std::string no_unload_oat_name = out_dir + "/nounload.oat";
1253   const std::string no_unload_vdex_name = out_dir + "/nounload.vdex";
1254   const std::string app_image_name = out_dir + "/unload.art";
1255   std::string error_msg;
1256   const std::vector<gc::space::ImageSpace*>& spaces = runtime->GetHeap()->GetBootImageSpaces();
1257   ASSERT_GT(spaces.size(), 0u);
1258   const std::string image_location = spaces[0]->GetImageLocation();
1259   // Without passing in an app image, it will unload in between compilations.
1260   const int res = GenerateOdexForTestWithStatus(
1261       GetLibCoreDexFileNames(),
1262       base_oat_name,
1263       CompilerFilter::Filter::kQuicken,
1264       &error_msg,
1265       {"--force-determinism", "--avoid-storing-invocation"});
1266   ASSERT_EQ(res, 0);
1267   Copy(base_oat_name, unload_oat_name);
1268   Copy(base_vdex_name, unload_vdex_name);
1269   std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str()));
1270   std::unique_ptr<File> unload_vdex(OS::OpenFileForReading(unload_vdex_name.c_str()));
1271   ASSERT_TRUE(unload_oat != nullptr);
1272   ASSERT_TRUE(unload_vdex != nullptr);
1273   EXPECT_GT(unload_oat->GetLength(), 0u);
1274   EXPECT_GT(unload_vdex->GetLength(), 0u);
1275   // Regenerate with an app image to disable the dex2oat unloading and verify that the output is
1276   // the same.
1277   const int res2 = GenerateOdexForTestWithStatus(
1278       GetLibCoreDexFileNames(),
1279       base_oat_name,
1280       CompilerFilter::Filter::kQuicken,
1281       &error_msg,
1282       {"--force-determinism", "--avoid-storing-invocation", "--app-image-file=" + app_image_name});
1283   ASSERT_EQ(res2, 0);
1284   Copy(base_oat_name, no_unload_oat_name);
1285   Copy(base_vdex_name, no_unload_vdex_name);
1286   std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str()));
1287   std::unique_ptr<File> no_unload_vdex(OS::OpenFileForReading(no_unload_vdex_name.c_str()));
1288   ASSERT_TRUE(no_unload_oat != nullptr);
1289   ASSERT_TRUE(no_unload_vdex != nullptr);
1290   EXPECT_GT(no_unload_oat->GetLength(), 0u);
1291   EXPECT_GT(no_unload_vdex->GetLength(), 0u);
1292   // Verify that both of the files are the same (odex and vdex).
1293   EXPECT_EQ(unload_oat->GetLength(), no_unload_oat->GetLength());
1294   EXPECT_EQ(unload_vdex->GetLength(), no_unload_vdex->GetLength());
1295   EXPECT_EQ(unload_oat->Compare(no_unload_oat.get()), 0)
1296       << unload_oat_name << " " << no_unload_oat_name;
1297   EXPECT_EQ(unload_vdex->Compare(no_unload_vdex.get()), 0)
1298       << unload_vdex_name << " " << no_unload_vdex_name;
1299   // App image file.
1300   std::unique_ptr<File> app_image_file(OS::OpenFileForReading(app_image_name.c_str()));
1301   ASSERT_TRUE(app_image_file != nullptr);
1302   EXPECT_GT(app_image_file->GetLength(), 0u);
1303 }
1304 
1305 // Test that dexlayout section info is correctly written to the oat file for profile based
1306 // compilation.
TEST_F(Dex2oatTest,LayoutSections)1307 TEST_F(Dex2oatTest, LayoutSections) {
1308   using Hotness = ProfileCompilationInfo::MethodHotness;
1309   std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
1310   ScratchFile profile_file;
1311   // We can only layout method indices with code items, figure out which ones have this property
1312   // first.
1313   std::vector<uint16_t> methods;
1314   {
1315     const dex::TypeId* type_id = dex->FindTypeId("LManyMethods;");
1316     dex::TypeIndex type_idx = dex->GetIndexForTypeId(*type_id);
1317     ClassAccessor accessor(*dex, *dex->FindClassDef(type_idx));
1318     std::set<size_t> code_item_offsets;
1319     for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1320       const uint16_t method_idx = method.GetIndex();
1321       const size_t code_item_offset = method.GetCodeItemOffset();
1322       if (code_item_offsets.insert(code_item_offset).second) {
1323         // Unique code item, add the method index.
1324         methods.push_back(method_idx);
1325       }
1326     }
1327   }
1328   ASSERT_GE(methods.size(), 8u);
1329   std::vector<uint16_t> hot_methods = {methods[1], methods[3], methods[5]};
1330   std::vector<uint16_t> startup_methods = {methods[1], methods[2], methods[7]};
1331   std::vector<uint16_t> post_methods = {methods[0], methods[2], methods[6]};
1332   // Here, we build the profile from the method lists.
1333   ProfileCompilationInfo info;
1334   info.AddMethodsForDex(
1335       static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup),
1336       dex.get(),
1337       hot_methods.begin(),
1338       hot_methods.end());
1339   info.AddMethodsForDex(
1340       Hotness::kFlagStartup,
1341       dex.get(),
1342       startup_methods.begin(),
1343       startup_methods.end());
1344   info.AddMethodsForDex(
1345       Hotness::kFlagPostStartup,
1346       dex.get(),
1347       post_methods.begin(),
1348       post_methods.end());
1349   for (uint16_t id : hot_methods) {
1350     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot());
1351     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
1352   }
1353   for (uint16_t id : startup_methods) {
1354     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup());
1355   }
1356   for (uint16_t id : post_methods) {
1357     EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup());
1358   }
1359   // Save the profile since we want to use it with dex2oat to produce an oat file.
1360   ASSERT_TRUE(info.Save(profile_file.GetFd()));
1361   // Generate a profile based odex.
1362   const std::string dir = GetScratchDir();
1363   const std::string oat_filename = dir + "/base.oat";
1364   const std::string vdex_filename = dir + "/base.vdex";
1365   std::string error_msg;
1366   const int res = GenerateOdexForTestWithStatus(
1367       {dex->GetLocation()},
1368       oat_filename,
1369       CompilerFilter::Filter::kQuicken,
1370       &error_msg,
1371       {"--profile-file=" + profile_file.GetFilename()});
1372   EXPECT_EQ(res, 0);
1373 
1374   // Open our generated oat file.
1375   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
1376                                                    oat_filename.c_str(),
1377                                                    oat_filename.c_str(),
1378                                                    /*executable=*/ false,
1379                                                    /*low_4gb=*/ false,
1380                                                    dex->GetLocation(),
1381                                                    &error_msg));
1382   ASSERT_TRUE(odex_file != nullptr);
1383   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
1384   ASSERT_EQ(oat_dex_files.size(), 1u);
1385   // Check that the code sections match what we expect.
1386   for (const OatDexFile* oat_dex : oat_dex_files) {
1387     const DexLayoutSections* const sections = oat_dex->GetDexLayoutSections();
1388     // Testing of logging the sections.
1389     ASSERT_TRUE(sections != nullptr);
1390     LOG(INFO) << *sections;
1391 
1392     // Load the sections into temporary variables for convenience.
1393     const DexLayoutSection& code_section =
1394         sections->sections_[static_cast<size_t>(DexLayoutSections::SectionType::kSectionTypeCode)];
1395     const DexLayoutSection::Subsection& section_hot_code =
1396         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeHot)];
1397     const DexLayoutSection::Subsection& section_sometimes_used =
1398         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeSometimesUsed)];
1399     const DexLayoutSection::Subsection& section_startup_only =
1400         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeStartupOnly)];
1401     const DexLayoutSection::Subsection& section_unused =
1402         code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeUnused)];
1403 
1404     // All the sections should be non-empty.
1405     EXPECT_GT(section_hot_code.Size(), 0u);
1406     EXPECT_GT(section_sometimes_used.Size(), 0u);
1407     EXPECT_GT(section_startup_only.Size(), 0u);
1408     EXPECT_GT(section_unused.Size(), 0u);
1409 
1410     // Open the dex file since we need to peek at the code items to verify the layout matches what
1411     // we expect.
1412     std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
1413     ASSERT_TRUE(dex_file != nullptr) << error_msg;
1414     const dex::TypeId* type_id = dex_file->FindTypeId("LManyMethods;");
1415     ASSERT_TRUE(type_id != nullptr);
1416     dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
1417     const dex::ClassDef* class_def = dex_file->FindClassDef(type_idx);
1418     ASSERT_TRUE(class_def != nullptr);
1419 
1420     // Count how many code items are for each category, there should be at least one per category.
1421     size_t hot_count = 0;
1422     size_t post_startup_count = 0;
1423     size_t startup_count = 0;
1424     size_t unused_count = 0;
1425     // Visit all of the methdos of the main class and cross reference the method indices to their
1426     // corresponding code item offsets to verify the layout.
1427     ClassAccessor accessor(*dex_file, *class_def);
1428     for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1429       const size_t method_idx = method.GetIndex();
1430       const size_t code_item_offset = method.GetCodeItemOffset();
1431       const bool is_hot = ContainsElement(hot_methods, method_idx);
1432       const bool is_startup = ContainsElement(startup_methods, method_idx);
1433       const bool is_post_startup = ContainsElement(post_methods, method_idx);
1434       if (is_hot) {
1435         // Hot is highest precedence, check that the hot methods are in the hot section.
1436         EXPECT_TRUE(section_hot_code.Contains(code_item_offset));
1437         ++hot_count;
1438       } else if (is_post_startup) {
1439         // Post startup is sometimes used section.
1440         EXPECT_TRUE(section_sometimes_used.Contains(code_item_offset));
1441         ++post_startup_count;
1442       } else if (is_startup) {
1443         // Startup at this point means not hot or post startup, these must be startup only then.
1444         EXPECT_TRUE(section_startup_only.Contains(code_item_offset));
1445         ++startup_count;
1446       } else {
1447         if (section_unused.Contains(code_item_offset)) {
1448           // If no flags are set, the method should be unused ...
1449           ++unused_count;
1450         } else {
1451           // or this method is part of the last code item and the end is 4 byte aligned.
1452           for (const ClassAccessor::Method& method2 : accessor.GetMethods()) {
1453             EXPECT_LE(method2.GetCodeItemOffset(), code_item_offset);
1454           }
1455           uint32_t code_item_size = dex_file->FindCodeItemOffset(*class_def, method_idx);
1456           EXPECT_EQ((code_item_offset + code_item_size) % 4, 0u);
1457         }
1458       }
1459     }
1460     EXPECT_GT(hot_count, 0u);
1461     EXPECT_GT(post_startup_count, 0u);
1462     EXPECT_GT(startup_count, 0u);
1463     EXPECT_GT(unused_count, 0u);
1464   }
1465 }
1466 
1467 // Test that generating compact dex works.
TEST_F(Dex2oatTest,GenerateCompactDex)1468 TEST_F(Dex2oatTest, GenerateCompactDex) {
1469   // Generate a compact dex based odex.
1470   const std::string dir = GetScratchDir();
1471   const std::string oat_filename = dir + "/base.oat";
1472   const std::string vdex_filename = dir + "/base.vdex";
1473   const std::string dex_location = GetTestDexFileName("MultiDex");
1474   std::string error_msg;
1475   const int res = GenerateOdexForTestWithStatus(
1476       { dex_location },
1477       oat_filename,
1478       CompilerFilter::Filter::kQuicken,
1479       &error_msg,
1480       {"--compact-dex-level=fast"});
1481   EXPECT_EQ(res, 0);
1482   // Open our generated oat file.
1483   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
1484                                                    oat_filename.c_str(),
1485                                                    oat_filename.c_str(),
1486                                                    /*executable=*/ false,
1487                                                    /*low_4gb=*/ false,
1488                                                    dex_location,
1489                                                    &error_msg));
1490   ASSERT_TRUE(odex_file != nullptr);
1491   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
1492   ASSERT_GT(oat_dex_files.size(), 1u);
1493   // Check that each dex is a compact dex file.
1494   std::vector<std::unique_ptr<const CompactDexFile>> compact_dex_files;
1495   for (const OatDexFile* oat_dex : oat_dex_files) {
1496     std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
1497     ASSERT_TRUE(dex_file != nullptr) << error_msg;
1498     ASSERT_TRUE(dex_file->IsCompactDexFile());
1499     compact_dex_files.push_back(
1500         std::unique_ptr<const CompactDexFile>(dex_file.release()->AsCompactDexFile()));
1501   }
1502   for (const std::unique_ptr<const CompactDexFile>& dex_file : compact_dex_files) {
1503     // Test that every code item is in the owned section.
1504     const CompactDexFile::Header& header = dex_file->GetHeader();
1505     EXPECT_LE(header.OwnedDataBegin(), header.OwnedDataEnd());
1506     EXPECT_LE(header.OwnedDataBegin(), header.data_size_);
1507     EXPECT_LE(header.OwnedDataEnd(), header.data_size_);
1508     for (ClassAccessor accessor : dex_file->GetClasses()) {
1509       for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1510         if (method.GetCodeItemOffset() != 0u) {
1511           ASSERT_GE(method.GetCodeItemOffset(), header.OwnedDataBegin());
1512           ASSERT_LT(method.GetCodeItemOffset(), header.OwnedDataEnd());
1513         }
1514       }
1515     }
1516     // Test that the owned sections don't overlap.
1517     for (const std::unique_ptr<const CompactDexFile>& other_dex : compact_dex_files) {
1518       if (dex_file != other_dex) {
1519         ASSERT_TRUE(
1520             (dex_file->GetHeader().OwnedDataBegin() >= other_dex->GetHeader().OwnedDataEnd()) ||
1521             (dex_file->GetHeader().OwnedDataEnd() <= other_dex->GetHeader().OwnedDataBegin()));
1522       }
1523     }
1524   }
1525 }
1526 
1527 class Dex2oatVerifierAbort : public Dex2oatTest {};
1528 
TEST_F(Dex2oatVerifierAbort,HardFail)1529 TEST_F(Dex2oatVerifierAbort, HardFail) {
1530   // Use VerifierDeps as it has hard-failing classes.
1531   std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDeps"));
1532   std::string out_dir = GetScratchDir();
1533   const std::string base_oat_name = out_dir + "/base.oat";
1534   std::string error_msg;
1535   const int res_fail = GenerateOdexForTestWithStatus(
1536         {dex->GetLocation()},
1537         base_oat_name,
1538         CompilerFilter::Filter::kQuicken,
1539         &error_msg,
1540         {"--abort-on-hard-verifier-error"});
1541   EXPECT_NE(0, res_fail);
1542 
1543   const int res_no_fail = GenerateOdexForTestWithStatus(
1544         {dex->GetLocation()},
1545         base_oat_name,
1546         CompilerFilter::Filter::kQuicken,
1547         &error_msg,
1548         {"--no-abort-on-hard-verifier-error"});
1549   EXPECT_EQ(0, res_no_fail);
1550 }
1551 
TEST_F(Dex2oatVerifierAbort,SoftFail)1552 TEST_F(Dex2oatVerifierAbort, SoftFail) {
1553   // Use VerifierDepsMulti as it has hard-failing classes.
1554   std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDepsMulti"));
1555   std::string out_dir = GetScratchDir();
1556   const std::string base_oat_name = out_dir + "/base.oat";
1557   std::string error_msg;
1558   const int res_fail = GenerateOdexForTestWithStatus(
1559         {dex->GetLocation()},
1560         base_oat_name,
1561         CompilerFilter::Filter::kQuicken,
1562         &error_msg,
1563         {"--abort-on-soft-verifier-error"});
1564   EXPECT_NE(0, res_fail);
1565 
1566   const int res_no_fail = GenerateOdexForTestWithStatus(
1567         {dex->GetLocation()},
1568         base_oat_name,
1569         CompilerFilter::Filter::kQuicken,
1570         &error_msg,
1571         {"--no-abort-on-soft-verifier-error"});
1572   EXPECT_EQ(0, res_no_fail);
1573 }
1574 
1575 class Dex2oatDedupeCode : public Dex2oatTest {};
1576 
TEST_F(Dex2oatDedupeCode,DedupeTest)1577 TEST_F(Dex2oatDedupeCode, DedupeTest) {
1578   // Use MyClassNatives. It has lots of native methods that will produce deduplicate-able code.
1579   std::unique_ptr<const DexFile> dex(OpenTestDexFile("MyClassNatives"));
1580   std::string out_dir = GetScratchDir();
1581   const std::string base_oat_name = out_dir + "/base.oat";
1582   size_t no_dedupe_size = 0;
1583   ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
1584                                   base_oat_name,
1585                                   CompilerFilter::Filter::kSpeed,
1586                                   { "--deduplicate-code=false" },
1587                                   /*expect_success=*/ true,
1588                                   /*use_fd=*/ false,
1589                                   /*use_zip_fd=*/ false,
1590                                   [&no_dedupe_size](const OatFile& o) {
1591                                     no_dedupe_size = o.Size();
1592                                   }));
1593 
1594   size_t dedupe_size = 0;
1595   ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
1596                                   base_oat_name,
1597                                   CompilerFilter::Filter::kSpeed,
1598                                   { "--deduplicate-code=true" },
1599                                   /*expect_success=*/ true,
1600                                   /*use_fd=*/ false,
1601                                   /*use_zip_fd=*/ false,
1602                                   [&dedupe_size](const OatFile& o) {
1603                                     dedupe_size = o.Size();
1604                                   }));
1605 
1606   EXPECT_LT(dedupe_size, no_dedupe_size);
1607 }
1608 
TEST_F(Dex2oatTest,UncompressedTest)1609 TEST_F(Dex2oatTest, UncompressedTest) {
1610   std::unique_ptr<const DexFile> dex(OpenTestDexFile("MainUncompressedAligned"));
1611   std::string out_dir = GetScratchDir();
1612   const std::string base_oat_name = out_dir + "/base.oat";
1613   ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
1614                                   base_oat_name,
1615                                   CompilerFilter::Filter::kQuicken,
1616                                   { },
1617                                   /*expect_success=*/ true,
1618                                   /*use_fd=*/ false,
1619                                   /*use_zip_fd=*/ false,
1620                                   [](const OatFile& o) {
1621                                     CHECK(!o.ContainsDexCode());
1622                                   }));
1623 }
1624 
TEST_F(Dex2oatTest,EmptyUncompressedDexTest)1625 TEST_F(Dex2oatTest, EmptyUncompressedDexTest) {
1626   std::string out_dir = GetScratchDir();
1627   const std::string base_oat_name = out_dir + "/base.oat";
1628   std::string error_msg;
1629   int status = GenerateOdexForTestWithStatus(
1630       { GetTestDexFileName("MainEmptyUncompressed") },
1631       base_oat_name,
1632       CompilerFilter::Filter::kQuicken,
1633       &error_msg,
1634       { },
1635       /*use_fd*/ false);
1636   // Expect to fail with code 1 and not SIGSEGV or SIGABRT.
1637   ASSERT_TRUE(WIFEXITED(status));
1638   ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg;
1639 }
1640 
TEST_F(Dex2oatTest,EmptyUncompressedAlignedDexTest)1641 TEST_F(Dex2oatTest, EmptyUncompressedAlignedDexTest) {
1642   std::string out_dir = GetScratchDir();
1643   const std::string base_oat_name = out_dir + "/base.oat";
1644   std::string error_msg;
1645   int status = GenerateOdexForTestWithStatus(
1646       { GetTestDexFileName("MainEmptyUncompressedAligned") },
1647       base_oat_name,
1648       CompilerFilter::Filter::kQuicken,
1649       &error_msg,
1650       { },
1651       /*use_fd*/ false);
1652   // Expect to fail with code 1 and not SIGSEGV or SIGABRT.
1653   ASSERT_TRUE(WIFEXITED(status));
1654   ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg;
1655 }
1656 
1657 // Dex file that has duplicate methods have different code items and debug info.
1658 static const char kDuplicateMethodInputDex[] =
1659     "ZGV4CjAzOQDEy8VPdj4qHpgPYFWtLCtOykfFP4kB8tGYDAAAcAAAAHhWNBIAAAAAAAAAANALAABI"
1660     "AAAAcAAAAA4AAACQAQAABQAAAMgBAAANAAAABAIAABkAAABsAgAABAAAADQDAADgCAAAuAMAADgI"
1661     "AABCCAAASggAAE8IAABcCAAAaggAAHkIAACICAAAlggAAKQIAACyCAAAwAgAAM4IAADcCAAA6ggA"
1662     "APgIAAD7CAAA/wgAABcJAAAuCQAARQkAAFQJAAB4CQAAmAkAALsJAADSCQAA5gkAAPoJAAAVCgAA"
1663     "KQoAADsKAABCCgAASgoAAFIKAABbCgAAZAoAAGwKAAB0CgAAfAoAAIQKAACMCgAAlAoAAJwKAACk"
1664     "CgAArQoAALcKAADACgAAwwoAAMcKAADcCgAA6QoAAPEKAAD3CgAA/QoAAAMLAAAJCwAAEAsAABcL"
1665     "AAAdCwAAIwsAACkLAAAvCwAANQsAADsLAABBCwAARwsAAE0LAABSCwAAWwsAAF4LAABoCwAAbwsA"
1666     "ABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAC4AAAAwAAAA"
1667     "DwAAAAkAAAAAAAAAEAAAAAoAAACoBwAALgAAAAwAAAAAAAAALwAAAAwAAACoBwAALwAAAAwAAACw"
1668     "BwAAAgAJADUAAAACAAkANgAAAAIACQA3AAAAAgAJADgAAAACAAkAOQAAAAIACQA6AAAAAgAJADsA"
1669     "AAACAAkAPAAAAAIACQA9AAAAAgAJAD4AAAACAAkAPwAAAAIACQBAAAAACwAHAEIAAAAAAAIAAQAA"
1670     "AAAAAwAeAAAAAQACAAEAAAABAAMAHgAAAAIAAgAAAAAAAgACAAEAAAADAAIAAQAAAAMAAgAfAAAA"
1671     "AwACACAAAAADAAIAIQAAAAMAAgAiAAAAAwACACMAAAADAAIAJAAAAAMAAgAlAAAAAwACACYAAAAD"
1672     "AAIAJwAAAAMAAgAoAAAAAwACACkAAAADAAIAKgAAAAMABAA0AAAABwADAEMAAAAIAAIAAQAAAAoA"
1673     "AgABAAAACgABADIAAAAKAAAARQAAAAAAAAAAAAAACAAAAAAAAAAdAAAAaAcAALYHAAAAAAAAAQAA"
1674     "AAAAAAAIAAAAAAAAAB0AAAB4BwAAxAcAAAAAAAACAAAAAAAAAAgAAAAAAAAAHQAAAIgHAADSBwAA"
1675     "AAAAAAMAAAAAAAAACAAAAAAAAAAdAAAAmAcAAPoHAAAAAAAAAAAAAAEAAAAAAAAArAYAADEAAAAa"
1676     "AAMAaQAAABoABABpAAEAGgAHAGkABAAaAAgAaQAFABoACQBpAAYAGgAKAGkABwAaAAsAaQAIABoA"
1677     "DABpAAkAGgANAGkACgAaAA4AaQALABoABQBpAAIAGgAGAGkAAwAOAAAAAQABAAEAAACSBgAABAAA"
1678     "AHAQFQAAAA4ABAABAAIAAACWBgAAFwAAAGIADAAiAQoAcBAWAAEAGgICAG4gFwAhAG4gFwAxAG4Q"
1679     "GAABAAwBbiAUABAADgAAAAEAAQABAAAAngYAAAQAAABwEBUAAAAOAAIAAQACAAAAogYAAAYAAABi"
1680     "AAwAbiAUABAADgABAAEAAQAAAKgGAAAEAAAAcBAVAAAADgABAAEAAQAAALsGAAAEAAAAcBAVAAAA"
1681     "DgABAAAAAQAAAL8GAAAGAAAAYgAAAHEQAwAAAA4AAQAAAAEAAADEBgAABgAAAGIAAQBxEAMAAAAO"
1682     "AAEAAAABAAAA8QYAAAYAAABiAAIAcRABAAAADgABAAAAAQAAAPYGAAAGAAAAYgADAHEQAwAAAA4A"
1683     "AQAAAAEAAADJBgAABgAAAGIABABxEAMAAAAOAAEAAAABAAAAzgYAAAYAAABiAAEAcRADAAAADgAB"
1684     "AAAAAQAAANMGAAAGAAAAYgAGAHEQAwAAAA4AAQAAAAEAAADYBgAABgAAAGIABwBxEAMAAAAOAAEA"
1685     "AAABAAAA3QYAAAYAAABiAAgAcRABAAAADgABAAAAAQAAAOIGAAAGAAAAYgAJAHEQAwAAAA4AAQAA"
1686     "AAEAAADnBgAABgAAAGIACgBxEAMAAAAOAAEAAAABAAAA7AYAAAYAAABiAAsAcRABAAAADgABAAEA"
1687     "AAAAAPsGAAAlAAAAcQAHAAAAcQAIAAAAcQALAAAAcQAMAAAAcQANAAAAcQAOAAAAcQAPAAAAcQAQ"
1688     "AAAAcQARAAAAcQASAAAAcQAJAAAAcQAKAAAADgAnAA4AKQFFDgEWDwAhAA4AIwFFDloAEgAOABMA"
1689     "DktLS0tLS0tLS0tLABEADgAuAA5aADIADloANgAOWgA6AA5aAD4ADloAQgAOWgBGAA5aAEoADloA"
1690     "TgAOWgBSAA5aAFYADloAWgAOWgBeATQOPDw8PDw8PDw8PDw8AAIEAUYYAwIFAjEECEEXLAIFAjEE"
1691     "CEEXKwIFAjEECEEXLQIGAUYcAxgAGAEYAgAAAAIAAAAMBwAAEgcAAAIAAAAMBwAAGwcAAAIAAAAM"
1692     "BwAAJAcAAAEAAAAtBwAAPAcAAAAAAAAAAAAAAAAAAEgHAAAAAAAAAAAAAAAAAABUBwAAAAAAAAAA"
1693     "AAAAAAAAYAcAAAAAAAAAAAAAAAAAAAEAAAAJAAAAAQAAAA0AAAACAACAgASsCAEIxAgAAAIAAoCA"
1694     "BIQJAQicCQwAAgAACQEJAQkBCQEJAQkBCQEJAQkBCQEJAQkEiIAEuAcBgIAEuAkAAA4ABoCABNAJ"
1695     "AQnoCQAJhAoACaAKAAm8CgAJ2AoACfQKAAmQCwAJrAsACcgLAAnkCwAJgAwACZwMAAm4DAg8Y2xp"
1696     "bml0PgAGPGluaXQ+AANBQUEAC0hlbGxvIFdvcmxkAAxIZWxsbyBXb3JsZDEADUhlbGxvIFdvcmxk"
1697     "MTAADUhlbGxvIFdvcmxkMTEADEhlbGxvIFdvcmxkMgAMSGVsbG8gV29ybGQzAAxIZWxsbyBXb3Js"
1698     "ZDQADEhlbGxvIFdvcmxkNQAMSGVsbG8gV29ybGQ2AAxIZWxsbyBXb3JsZDcADEhlbGxvIFdvcmxk"
1699     "OAAMSGVsbG8gV29ybGQ5AAFMAAJMTAAWTE1hbnlNZXRob2RzJFByaW50ZXIyOwAVTE1hbnlNZXRo"
1700     "b2RzJFByaW50ZXI7ABVMTWFueU1ldGhvZHMkU3RyaW5nczsADUxNYW55TWV0aG9kczsAIkxkYWx2"
1701     "aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNs"
1702     "YXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNzZXM7ABVMamF2YS9pby9QcmludFN0"
1703     "cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5n"
1704     "L1N0cmluZ0J1aWxkZXI7ABJMamF2YS9sYW5nL1N5c3RlbTsAEE1hbnlNZXRob2RzLmphdmEABVBy"
1705     "aW50AAZQcmludDAABlByaW50MQAHUHJpbnQxMAAHUHJpbnQxMQAGUHJpbnQyAAZQcmludDMABlBy"
1706     "aW50NAAGUHJpbnQ1AAZQcmludDYABlByaW50NwAGUHJpbnQ4AAZQcmludDkAB1ByaW50ZXIACFBy"
1707     "aW50ZXIyAAdTdHJpbmdzAAFWAAJWTAATW0xqYXZhL2xhbmcvU3RyaW5nOwALYWNjZXNzRmxhZ3MA"
1708     "BmFwcGVuZAAEYXJncwAEbWFpbgAEbXNnMAAEbXNnMQAFbXNnMTAABW1zZzExAARtc2cyAARtc2cz"
1709     "AARtc2c0AARtc2c1AARtc2c2AARtc2c3AARtc2c4AARtc2c5AARuYW1lAANvdXQAB3ByaW50bG4A"
1710     "AXMACHRvU3RyaW5nAAV2YWx1ZQBffn5EOHsibWluLWFwaSI6MTAwMDAsInNoYS0xIjoiZmViODZj"
1711     "MDA2ZWZhY2YxZDc5ODRiODVlMTc5MGZlZjdhNzY3YWViYyIsInZlcnNpb24iOiJ2MS4xLjUtZGV2"
1712     "In0AEAAAAAAAAAABAAAAAAAAAAEAAABIAAAAcAAAAAIAAAAOAAAAkAEAAAMAAAAFAAAAyAEAAAQA"
1713     "AAANAAAABAIAAAUAAAAZAAAAbAIAAAYAAAAEAAAANAMAAAEgAAAUAAAAuAMAAAMgAAAUAAAAkgYA"
1714     "AAQgAAAFAAAADAcAAAMQAAAEAAAAOQcAAAYgAAAEAAAAaAcAAAEQAAACAAAAqAcAAAAgAAAEAAAA"
1715     "tgcAAAIgAABIAAAAOAgAAAAQAAABAAAA0AsAAAAAAAA=";
1716 
WriteBase64ToFile(const char * base64,File * file)1717 static void WriteBase64ToFile(const char* base64, File* file) {
1718   // Decode base64.
1719   CHECK(base64 != nullptr);
1720   size_t length;
1721   std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
1722   CHECK(bytes != nullptr);
1723   if (!file->WriteFully(bytes.get(), length)) {
1724     PLOG(FATAL) << "Failed to write base64 as file";
1725   }
1726 }
1727 
TEST_F(Dex2oatTest,CompactDexGenerationFailure)1728 TEST_F(Dex2oatTest, CompactDexGenerationFailure) {
1729   ScratchFile temp_dex;
1730   WriteBase64ToFile(kDuplicateMethodInputDex, temp_dex.GetFile());
1731   std::string out_dir = GetScratchDir();
1732   const std::string oat_filename = out_dir + "/base.oat";
1733   // The dex won't pass the method verifier, only use the verify filter.
1734   ASSERT_TRUE(GenerateOdexForTest(temp_dex.GetFilename(),
1735                                   oat_filename,
1736                                   CompilerFilter::Filter::kVerify,
1737                                   { },
1738                                   /*expect_success=*/ true,
1739                                   /*use_fd=*/ false,
1740                                   /*use_zip_fd=*/ false,
1741                                   [](const OatFile& o) {
1742                                     CHECK(o.ContainsDexCode());
1743                                   }));
1744   // Open our generated oat file.
1745   std::string error_msg;
1746   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
1747                                                    oat_filename.c_str(),
1748                                                    oat_filename.c_str(),
1749                                                    /*executable=*/ false,
1750                                                    /*low_4gb=*/ false,
1751                                                    temp_dex.GetFilename(),
1752                                                    &error_msg));
1753   ASSERT_TRUE(odex_file != nullptr);
1754   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
1755   ASSERT_EQ(oat_dex_files.size(), 1u);
1756   // The dexes should have failed to convert to compact dex.
1757   for (const OatDexFile* oat_dex : oat_dex_files) {
1758     std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
1759     ASSERT_TRUE(dex_file != nullptr) << error_msg;
1760     ASSERT_TRUE(!dex_file->IsCompactDexFile());
1761   }
1762 }
1763 
TEST_F(Dex2oatTest,CompactDexGenerationFailureMultiDex)1764 TEST_F(Dex2oatTest, CompactDexGenerationFailureMultiDex) {
1765   // Create a multidex file with only one dex that gets rejected for cdex conversion.
1766   ScratchFile apk_file;
1767   {
1768     FILE* file = fdopen(DupCloexec(apk_file.GetFd()), "w+b");
1769     ZipWriter writer(file);
1770     // Add vdex to zip.
1771     writer.StartEntry("classes.dex", ZipWriter::kCompress);
1772     size_t length = 0u;
1773     std::unique_ptr<uint8_t[]> bytes(DecodeBase64(kDuplicateMethodInputDex, &length));
1774     ASSERT_GE(writer.WriteBytes(&bytes[0], length), 0);
1775     writer.FinishEntry();
1776     writer.StartEntry("classes2.dex", ZipWriter::kCompress);
1777     std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
1778     ASSERT_GE(writer.WriteBytes(dex->Begin(), dex->Size()), 0);
1779     writer.FinishEntry();
1780     writer.Finish();
1781     ASSERT_EQ(apk_file.GetFile()->Flush(), 0);
1782   }
1783   const std::string& dex_location = apk_file.GetFilename();
1784   const std::string odex_location = GetOdexDir() + "/output.odex";
1785   ASSERT_TRUE(GenerateOdexForTest(dex_location,
1786                                   odex_location,
1787                                   CompilerFilter::kQuicken,
1788                                   { "--compact-dex-level=fast" },
1789                                   true));
1790 }
1791 
TEST_F(Dex2oatTest,StderrLoggerOutput)1792 TEST_F(Dex2oatTest, StderrLoggerOutput) {
1793   std::string dex_location = GetScratchDir() + "/Dex2OatStderrLoggerTest.jar";
1794   std::string odex_location = GetOdexDir() + "/Dex2OatStderrLoggerTest.odex";
1795 
1796   // Test file doesn't matter.
1797   Copy(GetDexSrc1(), dex_location);
1798 
1799   ASSERT_TRUE(GenerateOdexForTest(dex_location,
1800                                   odex_location,
1801                                   CompilerFilter::kQuicken,
1802                                   { "--runtime-arg", "-Xuse-stderr-logger" },
1803                                   true));
1804   // Look for some random part of dex2oat logging. With the stderr logger this should be captured,
1805   // even on device.
1806   EXPECT_NE(std::string::npos, output_.find("dex2oat took"));
1807 }
1808 
TEST_F(Dex2oatTest,VerifyCompilationReason)1809 TEST_F(Dex2oatTest, VerifyCompilationReason) {
1810   std::string dex_location = GetScratchDir() + "/Dex2OatCompilationReason.jar";
1811   std::string odex_location = GetOdexDir() + "/Dex2OatCompilationReason.odex";
1812 
1813   // Test file doesn't matter.
1814   Copy(GetDexSrc1(), dex_location);
1815 
1816   ASSERT_TRUE(GenerateOdexForTest(dex_location,
1817                                   odex_location,
1818                                   CompilerFilter::kVerify,
1819                                   { "--compilation-reason=install" },
1820                                   true));
1821   std::string error_msg;
1822   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
1823                                                    odex_location.c_str(),
1824                                                    odex_location.c_str(),
1825                                                    /*executable=*/ false,
1826                                                    /*low_4gb=*/ false,
1827                                                    dex_location,
1828                                                    &error_msg));
1829   ASSERT_TRUE(odex_file != nullptr);
1830   ASSERT_STREQ("install", odex_file->GetCompilationReason());
1831 }
1832 
TEST_F(Dex2oatTest,VerifyNoCompilationReason)1833 TEST_F(Dex2oatTest, VerifyNoCompilationReason) {
1834   std::string dex_location = GetScratchDir() + "/Dex2OatNoCompilationReason.jar";
1835   std::string odex_location = GetOdexDir() + "/Dex2OatNoCompilationReason.odex";
1836 
1837   // Test file doesn't matter.
1838   Copy(GetDexSrc1(), dex_location);
1839 
1840   ASSERT_TRUE(GenerateOdexForTest(dex_location,
1841                                   odex_location,
1842                                   CompilerFilter::kVerify,
1843                                   {},
1844                                   true));
1845   std::string error_msg;
1846   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
1847                                                    odex_location.c_str(),
1848                                                    odex_location.c_str(),
1849                                                    /*executable=*/ false,
1850                                                    /*low_4gb=*/ false,
1851                                                    dex_location,
1852                                                    &error_msg));
1853   ASSERT_TRUE(odex_file != nullptr);
1854   ASSERT_EQ(nullptr, odex_file->GetCompilationReason());
1855 }
1856 
TEST_F(Dex2oatTest,DontExtract)1857 TEST_F(Dex2oatTest, DontExtract) {
1858   std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
1859   std::string error_msg;
1860   const std::string out_dir = GetScratchDir();
1861   const std::string dex_location = dex->GetLocation();
1862   const std::string odex_location = out_dir + "/base.oat";
1863   const std::string vdex_location = out_dir + "/base.vdex";
1864   ASSERT_TRUE(GenerateOdexForTest(dex_location,
1865                                   odex_location,
1866                                   CompilerFilter::Filter::kVerify,
1867                                   { "--copy-dex-files=false" },
1868                                   /*expect_success=*/ true,
1869                                   /*use_fd=*/ false,
1870                                   /*use_zip_fd=*/ false,
1871                                   [](const OatFile&) {}));
1872   {
1873     // Check the vdex doesn't have dex.
1874     std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
1875                                                   /*writable=*/ false,
1876                                                   /*low_4gb=*/ false,
1877                                                   /*unquicken=*/ false,
1878                                                   &error_msg));
1879     ASSERT_TRUE(vdex != nullptr);
1880     EXPECT_FALSE(vdex->HasDexSection()) << output_;
1881   }
1882   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
1883                                                    odex_location.c_str(),
1884                                                    odex_location.c_str(),
1885                                                    /*executable=*/ false,
1886                                                    /*low_4gb=*/ false,
1887                                                    dex_location,
1888                                                    &error_msg));
1889   ASSERT_TRUE(odex_file != nullptr) << dex_location;
1890   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
1891   ASSERT_EQ(oat_dex_files.size(), 1u);
1892   // Verify that the oat file can still open the dex files.
1893   for (const OatDexFile* oat_dex : oat_dex_files) {
1894     std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg));
1895     ASSERT_TRUE(dex_file != nullptr) << error_msg;
1896   }
1897   // Create a dm file and use it to verify.
1898   // Add produced artifacts to a zip file that doesn't contain the classes.dex.
1899   ScratchFile dm_file;
1900   {
1901     std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_location.c_str()));
1902     ASSERT_TRUE(vdex_file != nullptr);
1903     ASSERT_GT(vdex_file->GetLength(), 0u);
1904     FILE* file = fdopen(DupCloexec(dm_file.GetFd()), "w+b");
1905     ZipWriter writer(file);
1906     auto write_all_bytes = [&](File* file) {
1907       std::unique_ptr<uint8_t[]> bytes(new uint8_t[file->GetLength()]);
1908       ASSERT_TRUE(file->ReadFully(&bytes[0], file->GetLength()));
1909       ASSERT_GE(writer.WriteBytes(&bytes[0], file->GetLength()), 0);
1910     };
1911     // Add vdex to zip.
1912     writer.StartEntry(VdexFile::kVdexNameInDmFile, ZipWriter::kCompress);
1913     write_all_bytes(vdex_file.get());
1914     writer.FinishEntry();
1915     writer.Finish();
1916     ASSERT_EQ(dm_file.GetFile()->Flush(), 0);
1917   }
1918 
1919   auto generate_and_check = [&](CompilerFilter::Filter filter) {
1920     output_.clear();
1921     ASSERT_TRUE(GenerateOdexForTest(dex_location,
1922                                     odex_location,
1923                                     filter,
1924                                     { "--dump-timings",
1925                                       "--dm-file=" + dm_file.GetFilename(),
1926                                       // Pass -Xuse-stderr-logger have dex2oat output in output_ on
1927                                       // target.
1928                                       "--runtime-arg",
1929                                       "-Xuse-stderr-logger" },
1930                                     /*expect_success=*/ true,
1931                                     /*use_fd=*/ false,
1932                                     /*use_zip_fd=*/ false,
1933                                     [](const OatFile& o) {
1934                                       CHECK(o.ContainsDexCode());
1935                                     }));
1936     // Check the output for "Fast verify", this is printed from --dump-timings.
1937     std::istringstream iss(output_);
1938     std::string line;
1939     bool found_fast_verify = false;
1940     const std::string kFastVerifyString = "Fast Verify";
1941     while (std::getline(iss, line) && !found_fast_verify) {
1942       found_fast_verify = found_fast_verify || line.find(kFastVerifyString) != std::string::npos;
1943     }
1944     EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_;
1945   };
1946 
1947   // Generate a quickened dex by using the input dm file to verify.
1948   generate_and_check(CompilerFilter::Filter::kQuicken);
1949   // Use verify compiler filter to sanity check that FastVerify works for that filter too.
1950   generate_and_check(CompilerFilter::Filter::kVerify);
1951 }
1952 
1953 // Test that dex files with quickened opcodes aren't dequickened.
TEST_F(Dex2oatTest,QuickenedInput)1954 TEST_F(Dex2oatTest, QuickenedInput) {
1955   std::string error_msg;
1956   ScratchFile temp_dex;
1957   MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [] (DexFile* dex) {
1958     bool mutated_successfully = false;
1959     // Change the dex instructions to make an opcode that spans past the end of the code item.
1960     for (ClassAccessor accessor : dex->GetClasses()) {
1961       for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1962         CodeItemInstructionAccessor instructions = method.GetInstructions();
1963         // Make a quickened instruction that doesn't run past the end of the code item.
1964         if (instructions.InsnsSizeInCodeUnits() > 2) {
1965           const_cast<Instruction&>(instructions.InstructionAt(0)).SetOpcode(
1966               Instruction::IGET_BYTE_QUICK);
1967           mutated_successfully = true;
1968         }
1969       }
1970     }
1971     CHECK(mutated_successfully)
1972         << "Failed to find candidate code item with only one code unit in last instruction.";
1973   });
1974 
1975   const std::string& dex_location = temp_dex.GetFilename();
1976   std::string odex_location = GetOdexDir() + "/quickened.odex";
1977   std::string vdex_location = GetOdexDir() + "/quickened.vdex";
1978   std::unique_ptr<File> vdex_output(OS::CreateEmptyFile(vdex_location.c_str()));
1979   // Quicken the dex
1980   {
1981     std::string input_vdex = "--input-vdex-fd=-1";
1982     std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_output->Fd());
1983     ASSERT_TRUE(GenerateOdexForTest(dex_location,
1984                                     odex_location,
1985                                     CompilerFilter::kQuicken,
1986                                     // Disable cdex since we want to compare against the original
1987                                     // dex file after unquickening.
1988                                     { input_vdex, output_vdex, kDisableCompactDex },
1989                                     /* expect_success= */ true,
1990                                     /* use_fd= */ true));
1991   }
1992   // Unquicken by running the verify compiler filter on the vdex file and verify it matches.
1993   std::string odex_location2 = GetOdexDir() + "/unquickened.odex";
1994   std::string vdex_location2 = GetOdexDir() + "/unquickened.vdex";
1995   std::unique_ptr<File> vdex_unquickened(OS::CreateEmptyFile(vdex_location2.c_str()));
1996   {
1997     std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_output->Fd());
1998     std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_unquickened->Fd());
1999     ASSERT_TRUE(GenerateOdexForTest(dex_location,
2000                                     odex_location2,
2001                                     CompilerFilter::kVerify,
2002                                     // Disable cdex to avoid needing to write out the shared
2003                                     // section.
2004                                     { input_vdex, output_vdex, kDisableCompactDex },
2005                                     /* expect_success= */ true,
2006                                     /* use_fd= */ true));
2007   }
2008   ASSERT_EQ(vdex_unquickened->Flush(), 0) << "Could not flush and close vdex file";
2009   {
2010     // Check that hte vdex has one dex and compare it to the original one.
2011     std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location2.c_str(),
2012                                                   /*writable*/ false,
2013                                                   /*low_4gb*/ false,
2014                                                   /*unquicken*/ false,
2015                                                   &error_msg));
2016     std::vector<std::unique_ptr<const DexFile>> dex_files;
2017     bool result = vdex->OpenAllDexFiles(&dex_files, &error_msg);
2018     ASSERT_TRUE(result) << error_msg;
2019     ASSERT_EQ(dex_files.size(), 1u) << error_msg;
2020     ScratchFile temp;
2021     ASSERT_TRUE(temp.GetFile()->WriteFully(dex_files[0]->Begin(), dex_files[0]->Size()));
2022     ASSERT_EQ(temp.GetFile()->Flush(), 0) << "Could not flush extracted dex";
2023     EXPECT_EQ(temp.GetFile()->Compare(temp_dex.GetFile()), 0);
2024   }
2025   ASSERT_EQ(vdex_output->FlushCloseOrErase(), 0) << "Could not flush and close";
2026   ASSERT_EQ(vdex_unquickened->FlushCloseOrErase(), 0) << "Could not flush and close";
2027 }
2028 
2029 // Test that compact dex generation with invalid dex files doesn't crash dex2oat. b/75970654
TEST_F(Dex2oatTest,CompactDexInvalidSource)2030 TEST_F(Dex2oatTest, CompactDexInvalidSource) {
2031   ScratchFile invalid_dex;
2032   {
2033     FILE* file = fdopen(DupCloexec(invalid_dex.GetFd()), "w+b");
2034     ZipWriter writer(file);
2035     writer.StartEntry("classes.dex", ZipWriter::kAlign32);
2036     DexFile::Header header = {};
2037     StandardDexFile::WriteMagic(header.magic_);
2038     StandardDexFile::WriteCurrentVersion(header.magic_);
2039     header.file_size_ = 4 * KB;
2040     header.data_size_ = 4 * KB;
2041     header.data_off_ = 10 * MB;
2042     header.map_off_ = 10 * MB;
2043     header.class_defs_off_ = 10 * MB;
2044     header.class_defs_size_ = 10000;
2045     ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
2046     writer.FinishEntry();
2047     writer.Finish();
2048     ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
2049   }
2050   const std::string& dex_location = invalid_dex.GetFilename();
2051   const std::string odex_location = GetOdexDir() + "/output.odex";
2052   std::string error_msg;
2053   int status = GenerateOdexForTestWithStatus(
2054       {dex_location},
2055       odex_location,
2056       CompilerFilter::kQuicken,
2057       &error_msg,
2058       { "--compact-dex-level=fast" });
2059   ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
2060 }
2061 
2062 // Test that dex2oat with a CompactDex file in the APK fails.
TEST_F(Dex2oatTest,CompactDexInZip)2063 TEST_F(Dex2oatTest, CompactDexInZip) {
2064   CompactDexFile::Header header = {};
2065   CompactDexFile::WriteMagic(header.magic_);
2066   CompactDexFile::WriteCurrentVersion(header.magic_);
2067   header.file_size_ = sizeof(CompactDexFile::Header);
2068   header.data_off_ = 10 * MB;
2069   header.map_off_ = 10 * MB;
2070   header.class_defs_off_ = 10 * MB;
2071   header.class_defs_size_ = 10000;
2072   // Create a zip containing the invalid dex.
2073   ScratchFile invalid_dex_zip;
2074   {
2075     FILE* file = fdopen(DupCloexec(invalid_dex_zip.GetFd()), "w+b");
2076     ZipWriter writer(file);
2077     writer.StartEntry("classes.dex", ZipWriter::kCompress);
2078     ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0);
2079     writer.FinishEntry();
2080     writer.Finish();
2081     ASSERT_EQ(invalid_dex_zip.GetFile()->Flush(), 0);
2082   }
2083   // Create the dex file directly.
2084   ScratchFile invalid_dex;
2085   {
2086     ASSERT_GE(invalid_dex.GetFile()->WriteFully(&header, sizeof(header)), 0);
2087     ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
2088   }
2089   std::string error_msg;
2090   int status = 0u;
2091 
2092   status = GenerateOdexForTestWithStatus(
2093       { invalid_dex_zip.GetFilename() },
2094       GetOdexDir() + "/output_apk.odex",
2095       CompilerFilter::kQuicken,
2096       &error_msg,
2097       { "--compact-dex-level=fast" });
2098   ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
2099 
2100   status = GenerateOdexForTestWithStatus(
2101       { invalid_dex.GetFilename() },
2102       GetOdexDir() + "/output.odex",
2103       CompilerFilter::kQuicken,
2104       &error_msg,
2105       { "--compact-dex-level=fast" });
2106   ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
2107 }
2108 
TEST_F(Dex2oatTest,AppImageNoProfile)2109 TEST_F(Dex2oatTest, AppImageNoProfile) {
2110   ScratchFile app_image_file;
2111   const std::string out_dir = GetScratchDir();
2112   const std::string odex_location = out_dir + "/base.odex";
2113   ASSERT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
2114                                   odex_location,
2115                                   CompilerFilter::Filter::kSpeedProfile,
2116                                   { "--app-image-fd=" + std::to_string(app_image_file.GetFd()) },
2117                                   /*expect_success=*/ true,
2118                                   /*use_fd=*/ false,
2119                                   /*use_zip_fd=*/ false,
2120                                   [](const OatFile&) {}));
2121   // Open our generated oat file.
2122   std::string error_msg;
2123   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
2124                                                    odex_location.c_str(),
2125                                                    odex_location.c_str(),
2126                                                    /*executable=*/ false,
2127                                                    /*low_4gb=*/ false,
2128                                                    &error_msg));
2129   ASSERT_TRUE(odex_file != nullptr);
2130   ImageHeader header = {};
2131   ASSERT_TRUE(app_image_file.GetFile()->PreadFully(
2132       reinterpret_cast<void*>(&header),
2133       sizeof(header),
2134       /*offset*/ 0u)) << app_image_file.GetFile()->GetLength();
2135   EXPECT_GT(header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u);
2136   EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtMethods).Size(), 0u);
2137   EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u);
2138 }
2139 
TEST_F(Dex2oatTest,ZipFd)2140 TEST_F(Dex2oatTest, ZipFd) {
2141   std::string zip_location = GetTestDexFileName("MainUncompressedAligned");
2142   std::unique_ptr<File> dex_file(OS::OpenFileForReading(zip_location.c_str()));
2143   std::vector<std::string> extra_args{
2144       StringPrintf("--zip-fd=%d", dex_file->Fd()),
2145       "--zip-location=" + zip_location,
2146   };
2147   std::string out_dir = GetScratchDir();
2148   const std::string base_oat_name = out_dir + "/base.oat";
2149   ASSERT_TRUE(GenerateOdexForTest(zip_location,
2150                                   base_oat_name,
2151                                   CompilerFilter::Filter::kQuicken,
2152                                   extra_args,
2153                                   /*expect_success=*/ true,
2154                                   /*use_fd=*/ false,
2155                                   /*use_zip_fd=*/ true));
2156 }
2157 
TEST_F(Dex2oatTest,AppImageEmptyDex)2158 TEST_F(Dex2oatTest, AppImageEmptyDex) {
2159   // Create a profile with the startup method marked.
2160   ScratchFile profile_file;
2161   ScratchFile temp_dex;
2162   const std::string& dex_location = temp_dex.GetFilename();
2163   std::vector<uint16_t> methods;
2164   std::vector<dex::TypeIndex> classes;
2165   {
2166     MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("StringLiterals"), [&] (DexFile* dex) {
2167       // Modify the header to make the dex file valid but empty.
2168       DexFile::Header* header = const_cast<DexFile::Header*>(&dex->GetHeader());
2169       header->string_ids_size_ = 0;
2170       header->string_ids_off_ = 0;
2171       header->type_ids_size_ = 0;
2172       header->type_ids_off_ = 0;
2173       header->proto_ids_size_ = 0;
2174       header->proto_ids_off_ = 0;
2175       header->field_ids_size_ = 0;
2176       header->field_ids_off_ = 0;
2177       header->method_ids_size_ = 0;
2178       header->method_ids_off_ = 0;
2179       header->class_defs_size_ = 0;
2180       header->class_defs_off_ = 0;
2181       ASSERT_GT(header->file_size_,
2182                 sizeof(*header) + sizeof(dex::MapList) + sizeof(dex::MapItem) * 2);
2183       // Move map list to be right after the header.
2184       header->map_off_ = sizeof(DexFile::Header);
2185       dex::MapList* map_list = const_cast<dex::MapList*>(dex->GetMapList());
2186       map_list->list_[0].type_ = DexFile::kDexTypeHeaderItem;
2187       map_list->list_[0].size_ = 1u;
2188       map_list->list_[0].offset_ = 0u;
2189       map_list->list_[1].type_ = DexFile::kDexTypeMapList;
2190       map_list->list_[1].size_ = 1u;
2191       map_list->list_[1].offset_ = header->map_off_;
2192       map_list->size_ = 2;
2193       header->data_off_ = header->map_off_;
2194       header->data_size_ = map_list->Size();
2195     });
2196   }
2197   std::unique_ptr<const DexFile> dex_file(OpenDexFile(temp_dex.GetFilename().c_str()));
2198   const std::string out_dir = GetScratchDir();
2199   const std::string odex_location = out_dir + "/base.odex";
2200   const std::string app_image_location = out_dir + "/base.art";
2201   ASSERT_TRUE(GenerateOdexForTest(dex_location,
2202                                   odex_location,
2203                                   CompilerFilter::Filter::kSpeedProfile,
2204                                   { "--app-image-file=" + app_image_location,
2205                                     "--resolve-startup-const-strings=true",
2206                                     "--profile-file=" + profile_file.GetFilename()},
2207                                   /*expect_success=*/ true,
2208                                   /*use_fd=*/ false,
2209                                   /*use_zip_fd=*/ false,
2210                                   [](const OatFile&) {}));
2211   // Open our generated oat file.
2212   std::string error_msg;
2213   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
2214                                                    odex_location.c_str(),
2215                                                    odex_location.c_str(),
2216                                                    /*executable=*/ false,
2217                                                    /*low_4gb=*/ false,
2218                                                    &error_msg));
2219   ASSERT_TRUE(odex_file != nullptr);
2220 }
2221 
TEST_F(Dex2oatTest,DexFileFd)2222 TEST_F(Dex2oatTest, DexFileFd) {
2223   std::string error_msg;
2224   std::string zip_location = GetTestDexFileName("Main");
2225   std::unique_ptr<File> zip_file(OS::OpenFileForReading(zip_location.c_str()));
2226   ASSERT_NE(-1, zip_file->Fd());
2227 
2228   std::unique_ptr<ZipArchive> zip_archive(
2229       ZipArchive::OpenFromFd(zip_file->Release(), zip_location.c_str(), &error_msg));
2230   ASSERT_TRUE(zip_archive != nullptr);
2231 
2232   std::string entry_name = DexFileLoader::GetMultiDexClassesDexName(0);
2233   std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
2234   ASSERT_TRUE(entry != nullptr);
2235 
2236   ScratchFile dex_file;
2237   const std::string& dex_location = dex_file.GetFilename();
2238   const std::string base_oat_name = GetScratchDir() + "/base.oat";
2239 
2240   bool success = entry->ExtractToFile(*(dex_file.GetFile()), &error_msg);
2241   ASSERT_TRUE(success);
2242   ASSERT_EQ(0, lseek(dex_file.GetFd(), 0, SEEK_SET));
2243 
2244   std::vector<std::string> extra_args{
2245       StringPrintf("--zip-fd=%d", dex_file.GetFd()),
2246       "--zip-location=" + dex_location,
2247   };
2248   ASSERT_TRUE(GenerateOdexForTest(dex_location,
2249                                   base_oat_name,
2250                                   CompilerFilter::Filter::kQuicken,
2251                                   extra_args,
2252                                   /*expect_success=*/ true,
2253                                   /*use_fd=*/ false,
2254                                   /*use_zip_fd=*/ true));
2255 }
2256 
TEST_F(Dex2oatTest,AppImageResolveStrings)2257 TEST_F(Dex2oatTest, AppImageResolveStrings) {
2258   using Hotness = ProfileCompilationInfo::MethodHotness;
2259   // Create a profile with the startup method marked.
2260   ScratchFile profile_file;
2261   ScratchFile temp_dex;
2262   const std::string& dex_location = temp_dex.GetFilename();
2263   std::vector<uint16_t> methods;
2264   std::vector<dex::TypeIndex> classes;
2265   {
2266     MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("StringLiterals"), [&] (DexFile* dex) {
2267       bool mutated_successfully = false;
2268       // Change the dex instructions to make an opcode that spans past the end of the code item.
2269       for (ClassAccessor accessor : dex->GetClasses()) {
2270         if (accessor.GetDescriptor() == std::string("LStringLiterals$StartupClass;")) {
2271           classes.push_back(accessor.GetClassIdx());
2272         }
2273         for (const ClassAccessor::Method& method : accessor.GetMethods()) {
2274           std::string method_name(dex->GetMethodName(dex->GetMethodId(method.GetIndex())));
2275           CodeItemInstructionAccessor instructions = method.GetInstructions();
2276           if (method_name == "startUpMethod2") {
2277             // Make an instruction that runs past the end of the code item and verify that it
2278             // doesn't cause dex2oat to crash.
2279             ASSERT_TRUE(instructions.begin() != instructions.end());
2280             DexInstructionIterator last_instruction = instructions.begin();
2281             for (auto dex_it = instructions.begin(); dex_it != instructions.end(); ++dex_it) {
2282               last_instruction = dex_it;
2283             }
2284             ASSERT_EQ(last_instruction->SizeInCodeUnits(), 1u);
2285             // Set the opcode to something that will go past the end of the code item.
2286             const_cast<Instruction&>(last_instruction.Inst()).SetOpcode(
2287                 Instruction::CONST_STRING_JUMBO);
2288             mutated_successfully = true;
2289             // Test that the safe iterator doesn't go past the end.
2290             SafeDexInstructionIterator it2(instructions.begin(), instructions.end());
2291             while (!it2.IsErrorState()) {
2292               ++it2;
2293             }
2294             EXPECT_TRUE(it2 == last_instruction);
2295             EXPECT_TRUE(it2 < instructions.end());
2296             methods.push_back(method.GetIndex());
2297             mutated_successfully = true;
2298           } else if (method_name == "startUpMethod") {
2299             methods.push_back(method.GetIndex());
2300           }
2301         }
2302       }
2303       CHECK(mutated_successfully)
2304           << "Failed to find candidate code item with only one code unit in last instruction.";
2305     });
2306   }
2307   std::unique_ptr<const DexFile> dex_file(OpenDexFile(temp_dex.GetFilename().c_str()));
2308   {
2309     ASSERT_GT(classes.size(), 0u);
2310     ASSERT_GT(methods.size(), 0u);
2311     // Here, we build the profile from the method lists.
2312     ProfileCompilationInfo info;
2313     info.AddClassesForDex(dex_file.get(), classes.begin(), classes.end());
2314     info.AddMethodsForDex(Hotness::kFlagStartup, dex_file.get(), methods.begin(), methods.end());
2315     // Save the profile since we want to use it with dex2oat to produce an oat file.
2316     ASSERT_TRUE(info.Save(profile_file.GetFd()));
2317   }
2318   const std::string out_dir = GetScratchDir();
2319   const std::string odex_location = out_dir + "/base.odex";
2320   const std::string app_image_location = out_dir + "/base.art";
2321   ASSERT_TRUE(GenerateOdexForTest(dex_location,
2322                                   odex_location,
2323                                   CompilerFilter::Filter::kSpeedProfile,
2324                                   { "--app-image-file=" + app_image_location,
2325                                     "--resolve-startup-const-strings=true",
2326                                     "--profile-file=" + profile_file.GetFilename()},
2327                                   /*expect_success=*/ true,
2328                                   /*use_fd=*/ false,
2329                                   /*use_zip_fd=*/ false,
2330                                   [](const OatFile&) {}));
2331   // Open our generated oat file.
2332   std::string error_msg;
2333   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
2334                                                    odex_location.c_str(),
2335                                                    odex_location.c_str(),
2336                                                    /*executable=*/ false,
2337                                                    /*low_4gb=*/ false,
2338                                                    &error_msg));
2339   ASSERT_TRUE(odex_file != nullptr);
2340   // Check the strings in the app image intern table only contain the "startup" strigs.
2341   {
2342     ScopedObjectAccess soa(Thread::Current());
2343     std::unique_ptr<gc::space::ImageSpace> space =
2344         gc::space::ImageSpace::CreateFromAppImage(app_image_location.c_str(),
2345                                                   odex_file.get(),
2346                                                   &error_msg);
2347     ASSERT_TRUE(space != nullptr) << error_msg;
2348     std::set<std::string> seen;
2349     InternTable intern_table;
2350     intern_table.AddImageStringsToTable(space.get(), [&](InternTable::UnorderedSet& interns)
2351         REQUIRES_SHARED(Locks::mutator_lock_) {
2352       for (const GcRoot<mirror::String>& str : interns) {
2353         seen.insert(str.Read()->ToModifiedUtf8());
2354       }
2355     });
2356     // Ensure that the dex cache has a preresolved string array.
2357     std::set<std::string> preresolved_seen;
2358     bool saw_dexcache = false;
2359     space->GetLiveBitmap()->VisitAllMarked(
2360         [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
2361       if (obj->IsDexCache<kVerifyNone>()) {
2362         ObjPtr<mirror::DexCache> dex_cache = obj->AsDexCache();
2363         GcRoot<mirror::String>* preresolved_strings = dex_cache->GetPreResolvedStrings();
2364         ASSERT_EQ(dex_file->NumStringIds(), dex_cache->NumPreResolvedStrings());
2365         for (size_t i = 0; i < dex_cache->NumPreResolvedStrings(); ++i) {
2366           ObjPtr<mirror::String> string = preresolved_strings[i].Read<kWithoutReadBarrier>();
2367           if (string != nullptr) {
2368             preresolved_seen.insert(string->ToModifiedUtf8());
2369           }
2370         }
2371         saw_dexcache = true;
2372       }
2373     });
2374     ASSERT_TRUE(saw_dexcache);
2375     // Everything in the preresolved array should also be in the intern table.
2376     for (const std::string& str : preresolved_seen) {
2377       EXPECT_TRUE(seen.find(str) != seen.end());
2378     }
2379     // Normal methods
2380     EXPECT_TRUE(preresolved_seen.find("Loading ") != preresolved_seen.end());
2381     EXPECT_TRUE(preresolved_seen.find("Starting up") != preresolved_seen.end());
2382     EXPECT_TRUE(preresolved_seen.find("abcd.apk") != preresolved_seen.end());
2383     EXPECT_TRUE(seen.find("Unexpected error") == seen.end());
2384     EXPECT_TRUE(seen.find("Shutting down!") == seen.end());
2385     EXPECT_TRUE(preresolved_seen.find("Unexpected error") == preresolved_seen.end());
2386     EXPECT_TRUE(preresolved_seen.find("Shutting down!") == preresolved_seen.end());
2387     // Classes initializers
2388     EXPECT_TRUE(preresolved_seen.find("Startup init") != preresolved_seen.end());
2389     EXPECT_TRUE(seen.find("Other class init") == seen.end());
2390     EXPECT_TRUE(preresolved_seen.find("Other class init") == preresolved_seen.end());
2391     // Expect the sets match.
2392     EXPECT_GE(seen.size(), preresolved_seen.size());
2393 
2394     // Verify what strings are marked as boot image.
2395     std::set<std::string> boot_image_strings;
2396     std::set<std::string> app_image_strings;
2397 
2398     MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
2399     intern_table.VisitInterns([&](const GcRoot<mirror::String>& root)
2400         REQUIRES_SHARED(Locks::mutator_lock_) {
2401       boot_image_strings.insert(root.Read()->ToModifiedUtf8());
2402     }, /*visit_boot_images=*/true, /*visit_non_boot_images=*/false);
2403     intern_table.VisitInterns([&](const GcRoot<mirror::String>& root)
2404         REQUIRES_SHARED(Locks::mutator_lock_) {
2405       app_image_strings.insert(root.Read()->ToModifiedUtf8());
2406     }, /*visit_boot_images=*/false, /*visit_non_boot_images=*/true);
2407     EXPECT_EQ(boot_image_strings.size(), 0u);
2408     EXPECT_TRUE(app_image_strings == seen);
2409   }
2410 }
2411 
2412 
TEST_F(Dex2oatClassLoaderContextTest,StoredClassLoaderContext)2413 TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) {
2414   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
2415   const std::string out_dir = GetScratchDir();
2416   const std::string odex_location = out_dir + "/base.odex";
2417   const std::string valid_context = "PCL[" + dex_files[0]->GetLocation() + "]";
2418   const std::string stored_context = "PCL[/system/not_real_lib.jar]";
2419   std::string expected_stored_context = "PCL[";
2420   size_t index = 1;
2421   for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
2422     const bool is_first = index == 1u;
2423     if (!is_first) {
2424       expected_stored_context += ":";
2425     }
2426     expected_stored_context += "/system/not_real_lib.jar";
2427     if (!is_first) {
2428       expected_stored_context += "!classes" + std::to_string(index) + ".dex";
2429     }
2430     expected_stored_context += "*" + std::to_string(dex_file->GetLocationChecksum());
2431     ++index;
2432   }
2433   expected_stored_context +=    + "]";
2434   // The class path should not be valid and should fail being stored.
2435   EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
2436                                   odex_location,
2437                                   CompilerFilter::Filter::kQuicken,
2438                                   { "--class-loader-context=" + stored_context },
2439                                   /*expect_success=*/ true,
2440                                   /*use_fd=*/ false,
2441                                   /*use_zip_fd=*/ false,
2442                                   [&](const OatFile& oat_file) {
2443     EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_;
2444     EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_;
2445   }));
2446   // The stored context should match what we expect even though it's invalid.
2447   EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
2448                                   odex_location,
2449                                   CompilerFilter::Filter::kQuicken,
2450                                   { "--class-loader-context=" + valid_context,
2451                                     "--stored-class-loader-context=" + stored_context },
2452                                   /*expect_success=*/ true,
2453                                   /*use_fd=*/ false,
2454                                   /*use_zip_fd=*/ false,
2455                                   [&](const OatFile& oat_file) {
2456     EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_;
2457   }));
2458 }
2459 
2460 class Dex2oatISAFeaturesRuntimeDetectionTest : public Dex2oatTest {
2461  protected:
RunTest(const std::vector<std::string> & extra_args={})2462   void RunTest(const std::vector<std::string>& extra_args = {}) {
2463     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
2464     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
2465 
2466     Copy(GetTestDexFileName(), dex_location);
2467 
2468     ASSERT_TRUE(GenerateOdexForTest(dex_location,
2469                                     odex_location,
2470                                     CompilerFilter::kSpeed,
2471                                     extra_args));
2472   }
2473 
GetTestDexFileName()2474   std::string GetTestDexFileName() {
2475     return GetDexSrc1();
2476   }
2477 };
2478 
TEST_F(Dex2oatISAFeaturesRuntimeDetectionTest,TestCurrentRuntimeFeaturesAsDex2OatArguments)2479 TEST_F(Dex2oatISAFeaturesRuntimeDetectionTest, TestCurrentRuntimeFeaturesAsDex2OatArguments) {
2480   std::vector<std::string> argv;
2481   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
2482   auto option_pos =
2483       std::find(std::begin(argv), std::end(argv), "--instruction-set-features=runtime");
2484   if (InstructionSetFeatures::IsRuntimeDetectionSupported()) {
2485     EXPECT_TRUE(kIsTargetBuild);
2486     EXPECT_NE(option_pos, std::end(argv));
2487   } else {
2488     EXPECT_EQ(option_pos, std::end(argv));
2489   }
2490 
2491   RunTest();
2492 }
2493 
2494 // Regression test for bug 179221298.
TEST_F(Dex2oatTest,LoadOutOfDateOatFile)2495 TEST_F(Dex2oatTest, LoadOutOfDateOatFile) {
2496   std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods"));
2497   std::string out_dir = GetScratchDir();
2498   const std::string base_oat_name = out_dir + "/base.oat";
2499   ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
2500                                   base_oat_name,
2501                                   CompilerFilter::Filter::kSpeed,
2502                                   { "--deduplicate-code=false" },
2503                                   /*expect_success=*/ true,
2504                                   /*use_fd=*/ false,
2505                                   /*use_zip_fd=*/ false));
2506 
2507   // Check that we can open the oat file as executable.
2508   {
2509     std::string error_msg;
2510     std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
2511                                                      base_oat_name.c_str(),
2512                                                      base_oat_name.c_str(),
2513                                                      /*executable=*/ true,
2514                                                      /*low_4gb=*/ false,
2515                                                      dex->GetLocation(),
2516                                                      &error_msg));
2517     ASSERT_TRUE(odex_file != nullptr) << error_msg;
2518   }
2519 
2520   // Rewrite the oat file with wrong version and bogus contents.
2521   {
2522     std::unique_ptr<File> file(OS::OpenFileReadWrite(base_oat_name.c_str()));
2523     ASSERT_TRUE(file != nullptr);
2524     // Retrieve the offset and size of the embedded oat file.
2525     size_t oatdata_offset;
2526     size_t oatdata_size;
2527     {
2528       std::string error_msg;
2529       std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.get(),
2530                                                       /*writable=*/ false,
2531                                                       /*program_header_only=*/ true,
2532                                                       /*low_4gb=*/ false,
2533                                                       &error_msg));
2534       ASSERT_TRUE(elf_file != nullptr) << error_msg;
2535       ASSERT_TRUE(elf_file->Load(file.get(),
2536                                  /*executable=*/ false,
2537                                  /*low_4gb=*/ false,
2538                                  /*reservation=*/ nullptr,
2539                                  &error_msg)) << error_msg;
2540       const uint8_t* base_address = elf_file->Is64Bit()
2541           ? elf_file->GetImpl64()->GetBaseAddress()
2542           : elf_file->GetImpl32()->GetBaseAddress();
2543       const uint8_t* oatdata = elf_file->FindDynamicSymbolAddress("oatdata");
2544       ASSERT_TRUE(oatdata != nullptr);
2545       ASSERT_TRUE(oatdata > base_address);
2546       // Note: We're assuming here that the virtual address offset is the same
2547       // as file offset. This is currently true for all oat files we generate.
2548       oatdata_offset = static_cast<size_t>(oatdata - base_address);
2549       const uint8_t* oatlastword = elf_file->FindDynamicSymbolAddress("oatlastword");
2550       ASSERT_TRUE(oatlastword != nullptr);
2551       ASSERT_TRUE(oatlastword > oatdata);
2552       oatdata_size = oatlastword - oatdata;
2553     }
2554 
2555     // Check that we have the right `oatdata_offset`.
2556     int64_t length = file->GetLength();
2557     ASSERT_GE(length, static_cast<ssize_t>(oatdata_offset + sizeof(OatHeader)));
2558     alignas(OatHeader) uint8_t header_data[sizeof(OatHeader)];
2559     ASSERT_TRUE(file->PreadFully(header_data, sizeof(header_data), oatdata_offset));
2560     const OatHeader& header = reinterpret_cast<const OatHeader&>(header_data);
2561     ASSERT_TRUE(header.IsValid()) << header.GetValidationErrorMessage();
2562 
2563     // Overwrite all oat data from version onwards with bytes with value 4.
2564     // (0x04040404 is not a valid version, we're using three decimal digits and '\0'.)
2565     //
2566     // We previously tried to find the value for key "debuggable" (bug 179221298)
2567     // in the key-value store before checking the oat header. This test tries to
2568     // ensure that such early processing of the key-value store shall crash.
2569     // Reading 0x04040404 as the size of the key-value store yields a bit over
2570     // 64MiB which should hopefully include some unmapped memory beyond the end
2571     // of the loaded oat file. Overwriting the whole embedded oat file ensures
2572     // that we do not match the key within the oat file but we could still
2573     // accidentally match it in the additional sections of the elf file, so this
2574     // approach could fail to catch similar issues. At the time of writing, this
2575     // test crashed when run without the fix on 64-bit host (but not 32-bit).
2576     static constexpr size_t kVersionOffset = sizeof(OatHeader::kOatMagic);
2577     static_assert(kVersionOffset < sizeof(OatHeader));
2578     std::vector<uint8_t> data(oatdata_size - kVersionOffset, 4u);
2579     ASSERT_TRUE(file->PwriteFully(data.data(), data.size(), oatdata_offset + kVersionOffset));
2580     UNUSED(oatdata_size);
2581     CHECK_EQ(file->FlushClose(), 0) << "Could not flush and close oat file";
2582   }
2583 
2584   // Check that we reject the oat file without crashing.
2585   {
2586     std::string error_msg;
2587     std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
2588                                                      base_oat_name.c_str(),
2589                                                      base_oat_name.c_str(),
2590                                                      /*executable=*/ true,
2591                                                      /*low_4gb=*/ false,
2592                                                      dex->GetLocation(),
2593                                                      &error_msg));
2594     ASSERT_FALSE(odex_file != nullptr);
2595   }
2596 }
2597 
2598 }  // namespace art
2599