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 <regex>
18 #include <sstream>
19 #include <string>
20 #include <vector>
21 
22 #include <sys/wait.h>
23 #include <unistd.h>
24 
25 #include "android-base/stringprintf.h"
26 
27 #include "common_runtime_test.h"
28 
29 #include "base/logging.h"
30 #include "base/macros.h"
31 #include "dex_file-inl.h"
32 #include "dex2oat_environment_test.h"
33 #include "dex2oat_return_codes.h"
34 #include "jit/profile_compilation_info.h"
35 #include "oat.h"
36 #include "oat_file.h"
37 #include "utils.h"
38 
39 namespace art {
40 
41 using android::base::StringPrintf;
42 
43 class Dex2oatTest : public Dex2oatEnvironmentTest {
44  public:
TearDown()45   virtual void TearDown() OVERRIDE {
46     Dex2oatEnvironmentTest::TearDown();
47 
48     output_ = "";
49     error_msg_ = "";
50     success_ = false;
51   }
52 
53  protected:
GenerateOdexForTestWithStatus(const std::string & dex_location,const std::string & odex_location,CompilerFilter::Filter filter,std::string * error_msg,const std::vector<std::string> & extra_args={},bool use_fd=false)54   int GenerateOdexForTestWithStatus(const std::string& dex_location,
55                                     const std::string& odex_location,
56                                     CompilerFilter::Filter filter,
57                                     std::string* error_msg,
58                                     const std::vector<std::string>& extra_args = {},
59                                     bool use_fd = false) {
60     std::unique_ptr<File> oat_file;
61     std::vector<std::string> args;
62     args.push_back("--dex-file=" + dex_location);
63     if (use_fd) {
64       oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
65       CHECK(oat_file != nullptr) << odex_location;
66       args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
67       args.push_back("--oat-location=" + odex_location);
68     } else {
69       args.push_back("--oat-file=" + odex_location);
70     }
71     args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
72     args.push_back("--runtime-arg");
73     args.push_back("-Xnorelocate");
74 
75     args.insert(args.end(), extra_args.begin(), extra_args.end());
76 
77     int status = Dex2Oat(args, error_msg);
78     if (oat_file != nullptr) {
79       CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
80     }
81     return status;
82   }
83 
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)84   void GenerateOdexForTest(const std::string& dex_location,
85                            const std::string& odex_location,
86                            CompilerFilter::Filter filter,
87                            const std::vector<std::string>& extra_args = {},
88                            bool expect_success = true,
89                            bool use_fd = false) {
90     std::string error_msg;
91     int status = GenerateOdexForTestWithStatus(dex_location,
92                                                odex_location,
93                                                filter,
94                                                &error_msg,
95                                                extra_args,
96                                                use_fd);
97     bool success = (status == 0);
98     if (expect_success) {
99       ASSERT_TRUE(success) << error_msg << std::endl << output_;
100 
101       // Verify the odex file was generated as expected.
102       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
103                                                        odex_location.c_str(),
104                                                        nullptr,
105                                                        nullptr,
106                                                        false,
107                                                        /*low_4gb*/false,
108                                                        dex_location.c_str(),
109                                                        &error_msg));
110       ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
111 
112       CheckFilter(filter, odex_file->GetCompilerFilter());
113     } else {
114       ASSERT_FALSE(success) << output_;
115 
116       error_msg_ = error_msg;
117 
118       // Verify there's no loadable odex file.
119       std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
120                                                        odex_location.c_str(),
121                                                        nullptr,
122                                                        nullptr,
123                                                        false,
124                                                        /*low_4gb*/false,
125                                                        dex_location.c_str(),
126                                                        &error_msg));
127       ASSERT_TRUE(odex_file.get() == nullptr);
128     }
129   }
130 
131   // Check the input compiler filter against the generated oat file's filter. Mayb be overridden
132   // in subclasses when equality is not expected.
CheckFilter(CompilerFilter::Filter expected,CompilerFilter::Filter actual)133   virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) {
134     EXPECT_EQ(expected, actual);
135   }
136 
Dex2Oat(const std::vector<std::string> & dex2oat_args,std::string * error_msg)137   int Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) {
138     Runtime* runtime = Runtime::Current();
139 
140     const std::vector<gc::space::ImageSpace*>& image_spaces =
141         runtime->GetHeap()->GetBootImageSpaces();
142     if (image_spaces.empty()) {
143       *error_msg = "No image location found for Dex2Oat.";
144       return false;
145     }
146     std::string image_location = image_spaces[0]->GetImageLocation();
147 
148     std::vector<std::string> argv;
149     argv.push_back(runtime->GetCompilerExecutable());
150     argv.push_back("--runtime-arg");
151     argv.push_back("-classpath");
152     argv.push_back("--runtime-arg");
153     std::string class_path = runtime->GetClassPathString();
154     if (class_path == "") {
155       class_path = OatFile::kSpecialSharedLibrary;
156     }
157     argv.push_back(class_path);
158     if (runtime->IsJavaDebuggable()) {
159       argv.push_back("--debuggable");
160     }
161     runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
162 
163     if (!runtime->IsVerificationEnabled()) {
164       argv.push_back("--compiler-filter=assume-verified");
165     }
166 
167     if (runtime->MustRelocateIfPossible()) {
168       argv.push_back("--runtime-arg");
169       argv.push_back("-Xrelocate");
170     } else {
171       argv.push_back("--runtime-arg");
172       argv.push_back("-Xnorelocate");
173     }
174 
175     if (!kIsTargetBuild) {
176       argv.push_back("--host");
177     }
178 
179     argv.push_back("--boot-image=" + image_location);
180 
181     std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
182     argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
183 
184     argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
185 
186     // We must set --android-root.
187     const char* android_root = getenv("ANDROID_ROOT");
188     CHECK(android_root != nullptr);
189     argv.push_back("--android-root=" + std::string(android_root));
190 
191     int link[2];
192 
193     if (pipe(link) == -1) {
194       return false;
195     }
196 
197     pid_t pid = fork();
198     if (pid == -1) {
199       return false;
200     }
201 
202     if (pid == 0) {
203       // We need dex2oat to actually log things.
204       setenv("ANDROID_LOG_TAGS", "*:d", 1);
205       dup2(link[1], STDERR_FILENO);
206       close(link[0]);
207       close(link[1]);
208       std::vector<const char*> c_args;
209       for (const std::string& str : argv) {
210         c_args.push_back(str.c_str());
211       }
212       c_args.push_back(nullptr);
213       execv(c_args[0], const_cast<char* const*>(c_args.data()));
214       exit(1);
215       UNREACHABLE();
216     } else {
217       close(link[1]);
218       char buffer[128];
219       memset(buffer, 0, 128);
220       ssize_t bytes_read = 0;
221 
222       while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) {
223         output_ += std::string(buffer, bytes_read);
224       }
225       close(link[0]);
226       int status = -1;
227       if (waitpid(pid, &status, 0) != -1) {
228         success_ = (status == 0);
229       }
230       return status;
231     }
232   }
233 
234   std::string output_ = "";
235   std::string error_msg_ = "";
236   bool success_ = false;
237 };
238 
239 class Dex2oatSwapTest : public Dex2oatTest {
240  protected:
RunTest(bool use_fd,bool expect_use,const std::vector<std::string> & extra_args={})241   void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) {
242     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
243     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
244 
245     Copy(GetTestDexFileName(), dex_location);
246 
247     std::vector<std::string> copy(extra_args);
248 
249     std::unique_ptr<ScratchFile> sf;
250     if (use_fd) {
251       sf.reset(new ScratchFile());
252       copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd()));
253     } else {
254       std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
255       copy.push_back("--swap-file=" + swap_location);
256     }
257     GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
258 
259     CheckValidity();
260     ASSERT_TRUE(success_);
261     CheckResult(expect_use);
262   }
263 
GetTestDexFileName()264   virtual std::string GetTestDexFileName() {
265     return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps");
266   }
267 
CheckResult(bool expect_use)268   virtual void CheckResult(bool expect_use) {
269     if (kIsTargetBuild) {
270       CheckTargetResult(expect_use);
271     } else {
272       CheckHostResult(expect_use);
273     }
274   }
275 
CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED)276   virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) {
277     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
278     //       something for variants with file descriptor where we can control the lifetime of
279     //       the swap file and thus take a look at it.
280   }
281 
CheckHostResult(bool expect_use)282   virtual void CheckHostResult(bool expect_use) {
283     if (!kIsTargetBuild) {
284       if (expect_use) {
285         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
286             << output_;
287       } else {
288         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
289             << output_;
290       }
291     }
292   }
293 
294   // Check whether the dex2oat run was really successful.
CheckValidity()295   virtual void CheckValidity() {
296     if (kIsTargetBuild) {
297       CheckTargetValidity();
298     } else {
299       CheckHostValidity();
300     }
301   }
302 
CheckTargetValidity()303   virtual void CheckTargetValidity() {
304     // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do
305     //       something for variants with file descriptor where we can control the lifetime of
306     //       the swap file and thus take a look at it.
307   }
308 
309   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()310   virtual void CheckHostValidity() {
311     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
312   }
313 };
314 
TEST_F(Dex2oatSwapTest,DoNotUseSwapDefaultSingleSmall)315 TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) {
316   RunTest(false /* use_fd */, false /* expect_use */);
317   RunTest(true /* use_fd */, false /* expect_use */);
318 }
319 
TEST_F(Dex2oatSwapTest,DoNotUseSwapSingle)320 TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) {
321   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
322   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" });
323 }
324 
TEST_F(Dex2oatSwapTest,DoNotUseSwapSmall)325 TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) {
326   RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
327   RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" });
328 }
329 
TEST_F(Dex2oatSwapTest,DoUseSwapSingleSmall)330 TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) {
331   RunTest(false /* use_fd */,
332           true /* expect_use */,
333           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
334   RunTest(true /* use_fd */,
335           true /* expect_use */,
336           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
337 }
338 
339 class Dex2oatSwapUseTest : public Dex2oatSwapTest {
340  protected:
CheckHostResult(bool expect_use)341   void CheckHostResult(bool expect_use) OVERRIDE {
342     if (!kIsTargetBuild) {
343       if (expect_use) {
344         EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos)
345             << output_;
346       } else {
347         EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos)
348             << output_;
349       }
350     }
351   }
352 
GetTestDexFileName()353   std::string GetTestDexFileName() OVERRIDE {
354     // Use Statics as it has a handful of functions.
355     return CommonRuntimeTest::GetTestDexFileName("Statics");
356   }
357 
GrabResult1()358   void GrabResult1() {
359     if (!kIsTargetBuild) {
360       native_alloc_1_ = ParseNativeAlloc();
361       swap_1_ = ParseSwap(false /* expected */);
362     } else {
363       native_alloc_1_ = std::numeric_limits<size_t>::max();
364       swap_1_ = 0;
365     }
366   }
367 
GrabResult2()368   void GrabResult2() {
369     if (!kIsTargetBuild) {
370       native_alloc_2_ = ParseNativeAlloc();
371       swap_2_ = ParseSwap(true /* expected */);
372     } else {
373       native_alloc_2_ = 0;
374       swap_2_ = std::numeric_limits<size_t>::max();
375     }
376   }
377 
378  private:
ParseNativeAlloc()379   size_t ParseNativeAlloc() {
380     std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)");
381     std::smatch native_alloc_match;
382     bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex);
383     if (!found) {
384       EXPECT_TRUE(found);
385       return 0;
386     }
387     if (native_alloc_match.size() != 2U) {
388       EXPECT_EQ(native_alloc_match.size(), 2U);
389       return 0;
390     }
391 
392     std::istringstream stream(native_alloc_match[1].str());
393     size_t value;
394     stream >> value;
395 
396     return value;
397   }
398 
ParseSwap(bool expected)399   size_t ParseSwap(bool expected) {
400     std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)");
401     std::smatch swap_match;
402     bool found = std::regex_search(output_, swap_match, swap_regex);
403     if (found != expected) {
404       EXPECT_EQ(expected, found);
405       return 0;
406     }
407 
408     if (!found) {
409       return 0;
410     }
411 
412     if (swap_match.size() != 2U) {
413       EXPECT_EQ(swap_match.size(), 2U);
414       return 0;
415     }
416 
417     std::istringstream stream(swap_match[1].str());
418     size_t value;
419     stream >> value;
420 
421     return value;
422   }
423 
424  protected:
425   size_t native_alloc_1_;
426   size_t native_alloc_2_;
427 
428   size_t swap_1_;
429   size_t swap_2_;
430 };
431 
TEST_F(Dex2oatSwapUseTest,CheckSwapUsage)432 TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
433   // The `native_alloc_2_ >= native_alloc_1_` assertion below may not
434   // hold true on some x86 systems; disable this test while we
435   // investigate (b/29259363).
436   TEST_DISABLED_FOR_X86();
437 
438   RunTest(false /* use_fd */,
439           false /* expect_use */);
440   GrabResult1();
441   std::string output_1 = output_;
442 
443   output_ = "";
444 
445   RunTest(false /* use_fd */,
446           true /* expect_use */,
447           { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" });
448   GrabResult2();
449   std::string output_2 = output_;
450 
451   if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) {
452     EXPECT_LT(native_alloc_2_, native_alloc_1_);
453     EXPECT_LT(swap_1_, swap_2_);
454 
455     LOG(ERROR) << output_1;
456     LOG(ERROR) << output_2;
457   }
458 }
459 
460 class Dex2oatVeryLargeTest : public Dex2oatTest {
461  protected:
CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,CompilerFilter::Filter result ATTRIBUTE_UNUSED)462   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
463                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
464     // Ignore, we'll do our own checks.
465   }
466 
RunTest(CompilerFilter::Filter filter,bool expect_large,const std::vector<std::string> & extra_args={})467   void RunTest(CompilerFilter::Filter filter,
468                bool expect_large,
469                const std::vector<std::string>& extra_args = {}) {
470     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
471     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
472 
473     Copy(GetDexSrc1(), dex_location);
474 
475     GenerateOdexForTest(dex_location, odex_location, filter, extra_args);
476 
477     CheckValidity();
478     ASSERT_TRUE(success_);
479     CheckResult(dex_location, odex_location, filter, expect_large);
480   }
481 
CheckResult(const std::string & dex_location,const std::string & odex_location,CompilerFilter::Filter filter,bool expect_large)482   void CheckResult(const std::string& dex_location,
483                    const std::string& odex_location,
484                    CompilerFilter::Filter filter,
485                    bool expect_large) {
486     // Host/target independent checks.
487     std::string error_msg;
488     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
489                                                      odex_location.c_str(),
490                                                      nullptr,
491                                                      nullptr,
492                                                      false,
493                                                      /*low_4gb*/false,
494                                                      dex_location.c_str(),
495                                                      &error_msg));
496     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
497     if (expect_large) {
498       // Note: we cannot check the following:
499       //   EXPECT_TRUE(CompilerFilter::IsAsGoodAs(CompilerFilter::kVerifyAtRuntime,
500       //                                          odex_file->GetCompilerFilter()));
501       // The reason is that the filter override currently happens when the dex files are
502       // loaded in dex2oat, which is after the oat file has been started. Thus, the header
503       // store cannot be changed, and the original filter is set in stone.
504 
505       for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
506         std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
507         ASSERT_TRUE(dex_file != nullptr);
508         uint32_t class_def_count = dex_file->NumClassDefs();
509         ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
510         for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
511           OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
512           EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled);
513         }
514       }
515 
516       // If the input filter was "below," it should have been used.
517       if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract, filter)) {
518         EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
519       }
520     } else {
521       EXPECT_EQ(odex_file->GetCompilerFilter(), filter);
522     }
523 
524     // Host/target dependent checks.
525     if (kIsTargetBuild) {
526       CheckTargetResult(expect_large);
527     } else {
528       CheckHostResult(expect_large);
529     }
530   }
531 
CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED)532   void CheckTargetResult(bool expect_large ATTRIBUTE_UNUSED) {
533     // TODO: Ignore for now. May do something for fd things.
534   }
535 
CheckHostResult(bool expect_large)536   void CheckHostResult(bool expect_large) {
537     if (!kIsTargetBuild) {
538       if (expect_large) {
539         EXPECT_NE(output_.find("Very large app, downgrading to extract."),
540                   std::string::npos)
541             << output_;
542       } else {
543         EXPECT_EQ(output_.find("Very large app, downgrading to extract."),
544                   std::string::npos)
545             << output_;
546       }
547     }
548   }
549 
550   // Check whether the dex2oat run was really successful.
CheckValidity()551   void CheckValidity() {
552     if (kIsTargetBuild) {
553       CheckTargetValidity();
554     } else {
555       CheckHostValidity();
556     }
557   }
558 
CheckTargetValidity()559   void CheckTargetValidity() {
560     // TODO: Ignore for now.
561   }
562 
563   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()564   void CheckHostValidity() {
565     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
566   }
567 };
568 
TEST_F(Dex2oatVeryLargeTest,DontUseVeryLarge)569 TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) {
570   RunTest(CompilerFilter::kAssumeVerified, false);
571   RunTest(CompilerFilter::kExtract, false);
572   RunTest(CompilerFilter::kQuicken, false);
573   RunTest(CompilerFilter::kSpeed, false);
574 
575   RunTest(CompilerFilter::kAssumeVerified, false, { "--very-large-app-threshold=1000000" });
576   RunTest(CompilerFilter::kExtract, false, { "--very-large-app-threshold=1000000" });
577   RunTest(CompilerFilter::kQuicken, false, { "--very-large-app-threshold=1000000" });
578   RunTest(CompilerFilter::kSpeed, false, { "--very-large-app-threshold=1000000" });
579 }
580 
TEST_F(Dex2oatVeryLargeTest,UseVeryLarge)581 TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) {
582   RunTest(CompilerFilter::kAssumeVerified, false, { "--very-large-app-threshold=100" });
583   RunTest(CompilerFilter::kExtract, false, { "--very-large-app-threshold=100" });
584   RunTest(CompilerFilter::kQuicken, true, { "--very-large-app-threshold=100" });
585   RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
586 }
587 
588 // Regressin test for b/35665292.
TEST_F(Dex2oatVeryLargeTest,SpeedProfileNoProfile)589 TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) {
590   // Test that dex2oat doesn't crash with speed-profile but no input profile.
591   RunTest(CompilerFilter::kSpeedProfile, false);
592 }
593 
594 class Dex2oatLayoutTest : public Dex2oatTest {
595  protected:
CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,CompilerFilter::Filter result ATTRIBUTE_UNUSED)596   void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
597                    CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
598     // Ignore, we'll do our own checks.
599   }
600 
601   // Emits a profile with a single dex file with the given location and a single class index of 1.
GenerateProfile(const std::string & test_profile,const std::string & dex_location,size_t num_classes,uint32_t checksum)602   void GenerateProfile(const std::string& test_profile,
603                        const std::string& dex_location,
604                        size_t num_classes,
605                        uint32_t checksum) {
606     int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644);
607     CHECK_GE(profile_test_fd, 0);
608 
609     ProfileCompilationInfo info;
610     std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location);
611     for (size_t i = 0; i < num_classes; ++i) {
612       info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i));
613     }
614     bool result = info.Save(profile_test_fd);
615     close(profile_test_fd);
616     ASSERT_TRUE(result);
617   }
618 
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)619   void CompileProfileOdex(const std::string& dex_location,
620                           const std::string& odex_location,
621                           const std::string& app_image_file_name,
622                           bool use_fd,
623                           size_t num_profile_classes,
624                           const std::vector<std::string>& extra_args = {},
625                           bool expect_success = true) {
626     const std::string profile_location = GetScratchDir() + "/primary.prof";
627     const char* location = dex_location.c_str();
628     std::string error_msg;
629     std::vector<std::unique_ptr<const DexFile>> dex_files;
630     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
631     EXPECT_EQ(dex_files.size(), 1U);
632     std::unique_ptr<const DexFile>& dex_file = dex_files[0];
633     GenerateProfile(profile_location,
634                     dex_location,
635                     num_profile_classes,
636                     dex_file->GetLocationChecksum());
637     std::vector<std::string> copy(extra_args);
638     copy.push_back("--profile-file=" + profile_location);
639     std::unique_ptr<File> app_image_file;
640     if (!app_image_file_name.empty()) {
641       if (use_fd) {
642         app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str()));
643         copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd()));
644       } else {
645         copy.push_back("--app-image-file=" + app_image_file_name);
646       }
647     }
648     GenerateOdexForTest(dex_location,
649                         odex_location,
650                         CompilerFilter::kSpeedProfile,
651                         copy,
652                         expect_success,
653                         use_fd);
654     if (app_image_file != nullptr) {
655       ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
656     }
657   }
658 
GetImageSize(const std::string & image_file_name)659   uint64_t GetImageSize(const std::string& image_file_name) {
660     EXPECT_FALSE(image_file_name.empty());
661     std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
662     CHECK(file != nullptr);
663     ImageHeader image_header;
664     const bool success = file->ReadFully(&image_header, sizeof(image_header));
665     CHECK(success);
666     CHECK(image_header.IsValid());
667     ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
668     return image_header.GetImageSize();
669   }
670 
RunTest(bool app_image)671   void RunTest(bool app_image) {
672     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
673     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
674     std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): "";
675     Copy(GetDexSrc2(), dex_location);
676 
677     uint64_t image_file_empty_profile = 0;
678     if (app_image) {
679       CompileProfileOdex(dex_location,
680                          odex_location,
681                          app_image_file,
682                          /* use_fd */ false,
683                          /* num_profile_classes */ 0);
684       CheckValidity();
685       ASSERT_TRUE(success_);
686       // Don't check the result since CheckResult relies on the class being in the profile.
687       image_file_empty_profile = GetImageSize(app_image_file);
688       EXPECT_GT(image_file_empty_profile, 0u);
689     }
690 
691     // Small profile.
692     CompileProfileOdex(dex_location,
693                        odex_location,
694                        app_image_file,
695                        /* use_fd */ false,
696                        /* num_profile_classes */ 1);
697     CheckValidity();
698     ASSERT_TRUE(success_);
699     CheckResult(dex_location, odex_location, app_image_file);
700 
701     if (app_image) {
702       // Test that the profile made a difference by adding more classes.
703       const uint64_t image_file_small_profile = GetImageSize(app_image_file);
704       CHECK_LT(image_file_empty_profile, image_file_small_profile);
705     }
706   }
707 
RunTestVDex()708   void RunTestVDex() {
709     std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
710     std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
711     std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
712     std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art";
713     Copy(GetDexSrc2(), dex_location);
714 
715     std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
716     CHECK(vdex_file1 != nullptr) << vdex_location;
717     ScratchFile vdex_file2;
718     {
719       std::string input_vdex = "--input-vdex-fd=-1";
720       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
721       CompileProfileOdex(dex_location,
722                          odex_location,
723                          app_image_file_name,
724                          /* use_fd */ true,
725                          /* num_profile_classes */ 1,
726                          { input_vdex, output_vdex });
727       EXPECT_GT(vdex_file1->GetLength(), 0u);
728     }
729     {
730       // Test that vdex and dexlayout fail gracefully.
731       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
732       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
733       CompileProfileOdex(dex_location,
734                          odex_location,
735                          app_image_file_name,
736                          /* use_fd */ true,
737                          /* num_profile_classes */ 1,
738                          { input_vdex, output_vdex },
739                          /* expect_success */ true);
740       EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
741     }
742     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
743     CheckValidity();
744     ASSERT_TRUE(success_);
745   }
746 
CheckResult(const std::string & dex_location,const std::string & odex_location,const std::string & app_image_file_name)747   void CheckResult(const std::string& dex_location,
748                    const std::string& odex_location,
749                    const std::string& app_image_file_name) {
750     // Host/target independent checks.
751     std::string error_msg;
752     std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
753                                                      odex_location.c_str(),
754                                                      nullptr,
755                                                      nullptr,
756                                                      false,
757                                                      /*low_4gb*/false,
758                                                      dex_location.c_str(),
759                                                      &error_msg));
760     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
761 
762     const char* location = dex_location.c_str();
763     std::vector<std::unique_ptr<const DexFile>> dex_files;
764     ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
765     EXPECT_EQ(dex_files.size(), 1U);
766     std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
767 
768     for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
769       std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
770       ASSERT_TRUE(new_dex_file != nullptr);
771       uint32_t class_def_count = new_dex_file->NumClassDefs();
772       ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
773       ASSERT_GE(class_def_count, 2U);
774 
775       // The new layout swaps the classes at indexes 0 and 1.
776       std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
777       std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
778       std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
779       std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
780       EXPECT_EQ(old_class0, new_class1);
781       EXPECT_EQ(old_class1, new_class0);
782     }
783 
784     EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
785 
786     if (!app_image_file_name.empty()) {
787       // Go peek at the image header to make sure it was large enough to contain the class.
788       std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str()));
789       ImageHeader image_header;
790       bool success = file->ReadFully(&image_header, sizeof(image_header));
791       ASSERT_TRUE(success);
792       ASSERT_TRUE(image_header.IsValid());
793       EXPECT_GT(image_header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u);
794     }
795   }
796 
797   // Check whether the dex2oat run was really successful.
CheckValidity()798   void CheckValidity() {
799     if (kIsTargetBuild) {
800       CheckTargetValidity();
801     } else {
802       CheckHostValidity();
803     }
804   }
805 
CheckTargetValidity()806   void CheckTargetValidity() {
807     // TODO: Ignore for now.
808   }
809 
810   // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
CheckHostValidity()811   void CheckHostValidity() {
812     EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
813   }
814 };
815 
TEST_F(Dex2oatLayoutTest,TestLayout)816 TEST_F(Dex2oatLayoutTest, TestLayout) {
817   RunTest(/* app-image */ false);
818 }
819 
TEST_F(Dex2oatLayoutTest,TestLayoutAppImage)820 TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) {
821   RunTest(/* app-image */ true);
822 }
823 
TEST_F(Dex2oatLayoutTest,TestVdexLayout)824 TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
825   RunTestVDex();
826 }
827 
828 class Dex2oatWatchdogTest : public Dex2oatTest {
829  protected:
RunTest(bool expect_success,const std::vector<std::string> & extra_args={})830   void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {
831     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
832     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
833 
834     Copy(GetTestDexFileName(), dex_location);
835 
836     std::vector<std::string> copy(extra_args);
837 
838     std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
839     copy.push_back("--swap-file=" + swap_location);
840     GenerateOdexForTest(dex_location,
841                         odex_location,
842                         CompilerFilter::kSpeed,
843                         copy,
844                         expect_success);
845   }
846 
GetTestDexFileName()847   std::string GetTestDexFileName() {
848     return GetDexSrc1();
849   }
850 };
851 
TEST_F(Dex2oatWatchdogTest,TestWatchdogOK)852 TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
853   // Check with default.
854   RunTest(true);
855 
856   // Check with ten minutes.
857   RunTest(true, { "--watchdog-timeout=600000" });
858 }
859 
TEST_F(Dex2oatWatchdogTest,TestWatchdogTrigger)860 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
861   // Check with ten milliseconds.
862   RunTest(false, { "--watchdog-timeout=10" });
863 }
864 
865 class Dex2oatReturnCodeTest : public Dex2oatTest {
866  protected:
RunTest(const std::vector<std::string> & extra_args={})867   int RunTest(const std::vector<std::string>& extra_args = {}) {
868     std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar";
869     std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex";
870 
871     Copy(GetTestDexFileName(), dex_location);
872 
873     std::string error_msg;
874     return GenerateOdexForTestWithStatus(dex_location,
875                                          odex_location,
876                                          CompilerFilter::kSpeed,
877                                          &error_msg,
878                                          extra_args);
879   }
880 
GetTestDexFileName()881   std::string GetTestDexFileName() {
882     return GetDexSrc1();
883   }
884 };
885 
TEST_F(Dex2oatReturnCodeTest,TestCreateRuntime)886 TEST_F(Dex2oatReturnCodeTest, TestCreateRuntime) {
887   int status = RunTest({ "--boot-image=/this/does/not/exist/yolo.oat" });
888   EXPECT_EQ(static_cast<int>(dex2oat::ReturnCode::kCreateRuntime), WEXITSTATUS(status)) << output_;
889 }
890 
891 }  // namespace art
892