1 /*
2  * Copyright (C) 2014 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 "oat_file_assistant.h"
18 
19 #include <sys/param.h>
20 
21 #include <string>
22 #include <vector>
23 #include <fcntl.h>
24 
25 #include <gtest/gtest.h>
26 
27 #include "android-base/strings.h"
28 
29 #include "art_field-inl.h"
30 #include "base/os.h"
31 #include "base/utils.h"
32 #include "class_linker-inl.h"
33 #include "class_loader_context.h"
34 #include "common_runtime_test.h"
35 #include "dexopt_test.h"
36 #include "hidden_api.h"
37 #include "oat.h"
38 #include "oat_file.h"
39 #include "oat_file_manager.h"
40 #include "scoped_thread_state_change-inl.h"
41 #include "thread-current-inl.h"
42 
43 namespace art {
44 
45 class OatFileAssistantTest : public DexoptTest {
46  public:
VerifyOptimizationStatus(const std::string & file,const std::string & expected_filter,const std::string & expected_reason)47   void VerifyOptimizationStatus(const std::string& file,
48                                 const std::string& expected_filter,
49                                 const std::string& expected_reason) {
50     std::string compilation_filter;
51     std::string compilation_reason;
52     OatFileAssistant::GetOptimizationStatus(
53         file, kRuntimeISA, &compilation_filter, &compilation_reason);
54 
55     ASSERT_EQ(expected_filter, compilation_filter);
56     ASSERT_EQ(expected_reason, compilation_reason);
57   }
58 
VerifyOptimizationStatus(const std::string & file,CompilerFilter::Filter expected_filter,const std::string & expected_reason)59   void VerifyOptimizationStatus(const std::string& file,
60                                 CompilerFilter::Filter expected_filter,
61                                 const std::string& expected_reason) {
62       VerifyOptimizationStatus(
63           file, CompilerFilter::NameOfFilter(expected_filter), expected_reason);
64   }
65 
InsertNewBootClasspathEntry()66   void InsertNewBootClasspathEntry() {
67     std::string extra_dex_filename = GetMultiDexSrc1();
68     Runtime* runtime = Runtime::Current();
69     runtime->boot_class_path_.push_back(extra_dex_filename);
70     if (!runtime->boot_class_path_locations_.empty()) {
71       runtime->boot_class_path_locations_.push_back(extra_dex_filename);
72     }
73   }
74 
GetDexOptNeeded(OatFileAssistant * assistant,CompilerFilter::Filter compiler_filter,bool profile_changed)75   int GetDexOptNeeded(OatFileAssistant* assistant,
76                       CompilerFilter::Filter compiler_filter,
77                       bool profile_changed) {
78     std::vector<int> context_fds;
79     return GetDexOptNeeded(assistant,
80         compiler_filter,
81         ClassLoaderContext::Default(),
82         context_fds,
83         profile_changed,
84         /*downgrade=*/ false);
85   }
86 
GetDexOptNeeded(OatFileAssistant * assistant,CompilerFilter::Filter compiler_filter,const std::unique_ptr<ClassLoaderContext> & context=ClassLoaderContext::Default (),const std::vector<int> & context_fds=std::vector<int> (),bool profile_changed=false,bool downgrade=false)87   int GetDexOptNeeded(
88       OatFileAssistant* assistant,
89       CompilerFilter::Filter compiler_filter,
90       const std::unique_ptr<ClassLoaderContext>& context = ClassLoaderContext::Default(),
91       const std::vector<int>& context_fds = std::vector<int>(),
92       bool profile_changed = false,
93       bool downgrade = false) {
94     return assistant->GetDexOptNeeded(
95         compiler_filter,
96         context.get(),
97         context_fds,
98         profile_changed,
99         downgrade);
100   }
101 };
102 
103 class ScopedNonWritable {
104  public:
ScopedNonWritable(const std::string & dex_location)105   explicit ScopedNonWritable(const std::string& dex_location) {
106     is_valid_ = false;
107     size_t pos = dex_location.rfind('/');
108     if (pos != std::string::npos) {
109       is_valid_ = true;
110       dex_parent_ = dex_location.substr(0, pos);
111       if (chmod(dex_parent_.c_str(), 0555) != 0)  {
112         PLOG(ERROR) << "Could not change permissions on " << dex_parent_;
113       }
114     }
115   }
116 
IsSuccessful()117   bool IsSuccessful() { return is_valid_ && (access(dex_parent_.c_str(), W_OK) != 0); }
118 
~ScopedNonWritable()119   ~ScopedNonWritable() {
120     if (is_valid_) {
121       if (chmod(dex_parent_.c_str(), 0777) != 0) {
122         PLOG(ERROR) << "Could not restore permissions on " << dex_parent_;
123       }
124     }
125   }
126 
127  private:
128   std::string dex_parent_;
129   bool is_valid_;
130 };
131 
IsExecutedAsRoot()132 static bool IsExecutedAsRoot() {
133   return geteuid() == 0;
134 }
135 
136 // Case: We have a MultiDEX file and up-to-date ODEX file for it with relative
137 // encoded dex locations.
138 // Expect: The oat file status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,RelativeEncodedDexLocation)139 TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
140   std::string dex_location = GetScratchDir() + "/RelativeEncodedDexLocation.jar";
141   std::string odex_location = GetOdexDir() + "/RelativeEncodedDexLocation.odex";
142 
143   // Create the dex file
144   Copy(GetMultiDexSrc1(), dex_location);
145 
146   // Create the oat file with relative encoded dex location.
147   std::vector<std::string> args = {
148     "--dex-file=" + dex_location,
149     "--dex-location=" + std::string("RelativeEncodedDexLocation.jar"),
150     "--oat-file=" + odex_location,
151     "--compiler-filter=speed"
152   };
153 
154   std::string error_msg;
155   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
156 
157   // Verify we can load both dex files.
158   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
159 
160   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
161   ASSERT_TRUE(oat_file.get() != nullptr);
162   EXPECT_TRUE(oat_file->IsExecutable());
163   std::vector<std::unique_ptr<const DexFile>> dex_files;
164   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
165   EXPECT_EQ(2u, dex_files.size());
166 }
167 
TEST_F(OatFileAssistantTest,MakeUpToDateWithContext)168 TEST_F(OatFileAssistantTest, MakeUpToDateWithContext) {
169   std::string dex_location = GetScratchDir() + "/TestDex.jar";
170   std::string odex_location = GetOdexDir() + "/TestDex.odex";
171   std::string context_location = GetScratchDir() + "/ContextDex.jar";
172   Copy(GetDexSrc1(), dex_location);
173   Copy(GetDexSrc2(), context_location);
174 
175   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
176 
177   std::string context_str = "PCL[" + context_location + "]";
178   std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
179   ASSERT_TRUE(context != nullptr);
180   ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, ""));
181 
182   std::string error_msg;
183   std::vector<std::string> args;
184   args.push_back("--dex-file=" + dex_location);
185   args.push_back("--oat-file=" + odex_location);
186   args.push_back("--class-loader-context=" + context_str);
187   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
188 
189   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
190   EXPECT_NE(nullptr, oat_file.get());
191   EXPECT_EQ(context->EncodeContextForOatFile(""),
192             oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
193 }
194 
TEST_F(OatFileAssistantTest,GetDexOptNeededWithUpToDateContextRelative)195 TEST_F(OatFileAssistantTest, GetDexOptNeededWithUpToDateContextRelative) {
196   std::string dex_location = GetScratchDir() + "/TestDex.jar";
197   std::string odex_location = GetOdexDir() + "/TestDex.odex";
198   std::string context_location = GetScratchDir() + "/ContextDex.jar";
199   Copy(GetDexSrc1(), dex_location);
200   Copy(GetDexSrc2(), context_location);
201 
202   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
203 
204   std::string context_str = "PCL[" + context_location + "]";
205   std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
206   ASSERT_TRUE(context != nullptr);
207   ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, ""));
208 
209   std::string error_msg;
210   std::vector<std::string> args;
211   args.push_back("--dex-file=" + dex_location);
212   args.push_back("--oat-file=" + odex_location);
213   args.push_back("--class-loader-context=" + context_str);
214   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
215 
216   // A relative context simulates a dependent split context.
217   std::unique_ptr<ClassLoaderContext> relative_context =
218       ClassLoaderContext::Create("PCL[ContextDex.jar]");
219   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
220             GetDexOptNeeded(&oat_file_assistant,
221                 CompilerFilter::kDefaultCompilerFilter,
222                 relative_context));
223 }
224 
225 // Case: We have a DEX file, but no OAT file for it.
226 // Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest,DexNoOat)227 TEST_F(OatFileAssistantTest, DexNoOat) {
228   std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
229   Copy(GetDexSrc1(), dex_location);
230 
231   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
232 
233   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
234       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
235   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
236       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
237   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
238       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile));
239   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
240       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
241 
242   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
243   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
244   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
245   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
246 
247   VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
248 }
249 
250 // Case: We have no DEX file and no OAT file.
251 // Expect: Status is kNoDexOptNeeded. Loading should fail, but not crash.
TEST_F(OatFileAssistantTest,NoDexNoOat)252 TEST_F(OatFileAssistantTest, NoDexNoOat) {
253   std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
254 
255   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
256 
257   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
258       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
259   EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
260 
261   // Trying to get the best oat file should fail, but not crash.
262   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
263   EXPECT_EQ(nullptr, oat_file.get());
264 }
265 
266 // Case: We have a DEX file and an ODEX file, but no OAT file.
267 // Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,OdexUpToDate)268 TEST_F(OatFileAssistantTest, OdexUpToDate) {
269   std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
270   std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
271   Copy(GetDexSrc1(), dex_location);
272   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
273 
274   // Force the use of oat location by making the dex parent not writable.
275   OatFileAssistant oat_file_assistant(
276       dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
277 
278   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
279             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
280   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
281             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
282   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
283             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
284   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
285             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
286 
287   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
288   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
289   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
290   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
291 
292   VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
293 }
294 
295 // Case: We have an ODEX file compiled against partial boot image.
296 // Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,OdexUpToDatePartialBootImage)297 TEST_F(OatFileAssistantTest, OdexUpToDatePartialBootImage) {
298   std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
299   std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
300   Copy(GetDexSrc1(), dex_location);
301   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
302 
303   // Insert an extra dex file to the boot class path.
304   InsertNewBootClasspathEntry();
305 
306   // Force the use of oat location by making the dex parent not writable.
307   OatFileAssistant oat_file_assistant(
308       dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
309 
310   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
311             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
312   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
313             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
314   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
315             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
316   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
317             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
318 
319   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
320   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
321   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
322   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
323 
324   VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
325 }
326 
327 // Case: We have a DEX file and a PIC ODEX file, but no OAT file. We load the dex
328 // file via a symlink.
329 // Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,OdexUpToDateSymLink)330 TEST_F(OatFileAssistantTest, OdexUpToDateSymLink) {
331   std::string scratch_dir = GetScratchDir();
332   std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
333   std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
334 
335   Copy(GetDexSrc1(), dex_location);
336   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
337 
338   // Now replace the dex location with a symlink.
339   std::string link = scratch_dir + "/link";
340   ASSERT_EQ(0, symlink(scratch_dir.c_str(), link.c_str()));
341   dex_location = link + "/OdexUpToDate.jar";
342 
343   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
344 
345   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
346       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
347   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
348       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
349   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
350       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
351   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
352       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
353 
354   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
355   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
356   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
357   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
358 }
359 
360 // Case: We have a DEX file and up-to-date OAT file for it.
361 // Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,OatUpToDate)362 TEST_F(OatFileAssistantTest, OatUpToDate) {
363   if (IsExecutedAsRoot()) {
364     // We cannot simulate non writable locations when executed as root: b/38000545.
365     LOG(ERROR) << "Test skipped because it's running as root";
366     return;
367   }
368 
369   std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
370   Copy(GetDexSrc1(), dex_location);
371   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
372 
373   // Force the use of oat location by making the dex parent not writable.
374   ScopedNonWritable scoped_non_writable(dex_location);
375   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
376 
377   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
378 
379   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
380       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
381   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
382       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
383   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
384       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
385   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
386       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
387 
388   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
389   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
390   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
391   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
392 
393   VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "unknown");
394 }
395 
396 // Case: Passing valid file descriptors of updated odex/vdex files along with the dex file.
397 // Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithFd)398 TEST_F(OatFileAssistantTest, GetDexOptNeededWithFd) {
399   std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
400   std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
401   std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
402 
403   Copy(GetDexSrc1(), dex_location);
404   GenerateOatForTest(dex_location.c_str(),
405                      odex_location.c_str(),
406                      CompilerFilter::kSpeed,
407                      /* with_alternate_image= */ false);
408 
409   android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY | O_CLOEXEC));
410   android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY | O_CLOEXEC));
411   android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
412 
413   OatFileAssistant oat_file_assistant(dex_location.c_str(),
414                                       kRuntimeISA,
415                                       false,
416                                       false,
417                                       vdex_fd.get(),
418                                       odex_fd.get(),
419                                       zip_fd.get());
420   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
421       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
422   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
423       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
424   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
425       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
426   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
427       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
428 
429   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
430   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
431   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
432   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
433 }
434 
435 // Case: Passing invalid odex fd and valid vdex and zip fds.
436 // Expect: The status should be kDex2OatForBootImage.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithInvalidOdexFd)437 TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexFd) {
438   std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
439   std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
440   std::string vdex_location = GetScratchDir() + "/OatUpToDate.vdex";
441 
442   Copy(GetDexSrc1(), dex_location);
443   GenerateOatForTest(dex_location.c_str(),
444                      odex_location.c_str(),
445                      CompilerFilter::kSpeed,
446                      /* with_alternate_image= */ false);
447 
448   android::base::unique_fd vdex_fd(open(vdex_location.c_str(), O_RDONLY | O_CLOEXEC));
449   android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
450 
451   OatFileAssistant oat_file_assistant(dex_location.c_str(),
452                                       kRuntimeISA,
453                                       false,
454                                       false,
455                                       vdex_fd.get(),
456                                       /* oat_fd= */ -1,
457                                       zip_fd.get());
458   EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
459       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
460   EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
461       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
462 
463   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
464   EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OdexFileStatus());
465   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
466   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
467 }
468 
469 // Case: Passing invalid vdex fd and valid odex and zip fds.
470 // Expect: The status should be kDex2OatFromScratch.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithInvalidVdexFd)471 TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidVdexFd) {
472   std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
473   std::string odex_location = GetScratchDir() + "/OatUpToDate.odex";
474 
475   Copy(GetDexSrc1(), dex_location);
476   GenerateOatForTest(dex_location.c_str(),
477                      odex_location.c_str(),
478                      CompilerFilter::kSpeed,
479                      /* with_alternate_image= */ false);
480 
481   android::base::unique_fd odex_fd(open(odex_location.c_str(), O_RDONLY | O_CLOEXEC));
482   android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
483 
484   OatFileAssistant oat_file_assistant(dex_location.c_str(),
485                                       kRuntimeISA,
486                                       false,
487                                       false,
488                                       /* vdex_fd= */ -1,
489                                       odex_fd.get(),
490                                       zip_fd.get());
491 
492   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
493       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
494   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
495   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
496   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
497   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
498 }
499 
500 // Case: Passing invalid vdex and odex fd with valid zip fd.
501 // Expect: The status is kDex2oatFromScratch.
TEST_F(OatFileAssistantTest,GetDexOptNeededWithInvalidOdexVdexFd)502 TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexVdexFd) {
503   std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
504 
505   Copy(GetDexSrc1(), dex_location);
506 
507   android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
508   OatFileAssistant oat_file_assistant(dex_location.c_str(),
509                                       kRuntimeISA,
510                                       false,
511                                       false,
512                                       /* vdex_fd= */ -1,
513                                       /* oat_fd= */ -1,
514                                       zip_fd);
515   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
516       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
517   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
518   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
519 }
520 
521 // Case: We have a DEX file and up-to-date (ODEX) VDEX file for it, but no
522 // ODEX file.
TEST_F(OatFileAssistantTest,VdexUpToDateNoOdex)523 TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) {
524   std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOdex.jar";
525   std::string odex_location = GetOdexDir() + "/VdexUpToDateNoOdex.oat";
526 
527   Copy(GetDexSrc1(), dex_location);
528 
529   // Generating and deleting the oat file should have the side effect of
530   // creating an up-to-date vdex file.
531   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
532   ASSERT_EQ(0, unlink(odex_location.c_str()));
533 
534   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
535 
536   // Even though the vdex file is up to date, because we don't have the oat
537   // file, we can't know that the vdex depends on the boot image and is up to
538   // date with respect to the boot image. Instead we must assume the vdex file
539   // depends on the boot image and is out of date with respect to the boot
540   // image.
541   EXPECT_EQ(-OatFileAssistant::kDex2OatForBootImage,
542       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
543 
544   // Make sure we don't crash in this case when we dump the status. We don't
545   // care what the actual dumped value is.
546   oat_file_assistant.GetStatusDump();
547 
548   VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
549 }
550 
551 // Case: We have a DEX file and empty VDEX and ODEX files.
TEST_F(OatFileAssistantTest,EmptyVdexOdex)552 TEST_F(OatFileAssistantTest, EmptyVdexOdex) {
553   std::string dex_location = GetScratchDir() + "/EmptyVdexOdex.jar";
554   std::string odex_location = GetOdexDir() + "/EmptyVdexOdex.oat";
555   std::string vdex_location = GetOdexDir() + "/EmptyVdexOdex.vdex";
556 
557   Copy(GetDexSrc1(), dex_location);
558   ScratchFile vdex_file(vdex_location.c_str());
559   ScratchFile odex_file(odex_location.c_str());
560 
561   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
562   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
563       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
564 }
565 
566 // Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT
567 // file.
TEST_F(OatFileAssistantTest,VdexUpToDateNoOat)568 TEST_F(OatFileAssistantTest, VdexUpToDateNoOat) {
569   if (IsExecutedAsRoot()) {
570     // We cannot simulate non writable locations when executed as root: b/38000545.
571     LOG(ERROR) << "Test skipped because it's running as root";
572     return;
573   }
574 
575   std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOat.jar";
576   std::string oat_location;
577   std::string error_msg;
578   ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
579         dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
580 
581   Copy(GetDexSrc1(), dex_location);
582   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
583   ASSERT_EQ(0, unlink(oat_location.c_str()));
584 
585   ScopedNonWritable scoped_non_writable(dex_location);
586   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
587   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
588 
589   // Even though the vdex file is up to date, because we don't have the oat
590   // file, we can't know that the vdex depends on the boot image and is up to
591   // date with respect to the boot image. Instead we must assume the vdex file
592   // depends on the boot image and is out of date with respect to the boot
593   // image.
594   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
595       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
596 }
597 
598 // Case: We have a DEX file and speed-profile OAT file for it.
599 // Expect: The status is kNoDexOptNeeded if the profile hasn't changed, but
600 // kDex2Oat if the profile has changed.
TEST_F(OatFileAssistantTest,ProfileOatUpToDate)601 TEST_F(OatFileAssistantTest, ProfileOatUpToDate) {
602   if (IsExecutedAsRoot()) {
603     // We cannot simulate non writable locations when executed as root: b/38000545.
604     LOG(ERROR) << "Test skipped because it's running as root";
605     return;
606   }
607 
608   std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar";
609   Copy(GetDexSrc1(), dex_location);
610   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
611 
612   ScopedNonWritable scoped_non_writable(dex_location);
613   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
614 
615   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
616 
617   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
618       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile, false));
619   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
620       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken, false));
621   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
622       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile, true));
623   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
624       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken, true));
625 
626   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
627   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
628   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
629   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
630 }
631 
632 // Case: We have a MultiDEX file and up-to-date OAT file for it.
633 // Expect: The status is kNoDexOptNeeded and we load all dex files.
TEST_F(OatFileAssistantTest,MultiDexOatUpToDate)634 TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
635   if (IsExecutedAsRoot()) {
636     // We cannot simulate non writable locations when executed as root: b/38000545.
637     LOG(ERROR) << "Test skipped because it's running as root";
638     return;
639   }
640 
641   std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
642   Copy(GetMultiDexSrc1(), dex_location);
643   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
644 
645   ScopedNonWritable scoped_non_writable(dex_location);
646   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
647 
648   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
649   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
650       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
651   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
652 
653   // Verify we can load both dex files.
654   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
655   ASSERT_TRUE(oat_file.get() != nullptr);
656   EXPECT_TRUE(oat_file->IsExecutable());
657   std::vector<std::unique_ptr<const DexFile>> dex_files;
658   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
659   EXPECT_EQ(2u, dex_files.size());
660 }
661 
662 // Case: We have a MultiDEX file where the non-main multdex entry is out of date.
663 // Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest,MultiDexNonMainOutOfDate)664 TEST_F(OatFileAssistantTest, MultiDexNonMainOutOfDate) {
665   if (IsExecutedAsRoot()) {
666     // We cannot simulate non writable locations when executed as root: b/38000545.
667     LOG(ERROR) << "Test skipped because it's running as root";
668     return;
669   }
670 
671   std::string dex_location = GetScratchDir() + "/MultiDexNonMainOutOfDate.jar";
672 
673   // Compile code for GetMultiDexSrc1.
674   Copy(GetMultiDexSrc1(), dex_location);
675   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
676 
677   // Now overwrite the dex file with GetMultiDexSrc2 so the non-main checksum
678   // is out of date.
679   Copy(GetMultiDexSrc2(), dex_location);
680 
681   ScopedNonWritable scoped_non_writable(dex_location);
682   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
683 
684   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
685   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
686       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
687   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
688 }
689 
690 // Case: We have a stripped MultiDEX file where the non-main multidex entry is
691 // out of date with respect to the odex file.
TEST_F(OatFileAssistantTest,StrippedMultiDexNonMainOutOfDate)692 TEST_F(OatFileAssistantTest, StrippedMultiDexNonMainOutOfDate) {
693   std::string dex_location = GetScratchDir() + "/StrippedMultiDexNonMainOutOfDate.jar";
694   std::string odex_location = GetOdexDir() + "/StrippedMultiDexNonMainOutOfDate.odex";
695 
696   // Compile the oat from GetMultiDexSrc1.
697   Copy(GetMultiDexSrc1(), dex_location);
698   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
699 
700   // Compile the odex from GetMultiDexSrc2, which has a different non-main
701   // dex checksum.
702   Copy(GetMultiDexSrc2(), dex_location);
703   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kQuicken);
704 
705   // Strip the dex file.
706   Copy(GetStrippedDexSrc1(), dex_location);
707 
708   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, /*load_executable=*/false);
709 
710   // Because the dex file is stripped, the odex file is considered the source
711   // of truth for the dex checksums. The oat file should be considered
712   // unusable.
713   std::unique_ptr<OatFile> best_file = oat_file_assistant.GetBestOatFile();
714   ASSERT_TRUE(best_file.get() != nullptr);
715   EXPECT_EQ(best_file->GetLocation(), odex_location);
716   EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
717   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
718   EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
719 }
720 
721 // Case: We have a DEX file and an OAT file out of date with respect to the
722 // dex checksum.
TEST_F(OatFileAssistantTest,OatDexOutOfDate)723 TEST_F(OatFileAssistantTest, OatDexOutOfDate) {
724   if (IsExecutedAsRoot()) {
725     // We cannot simulate non writable locations when executed as root: b/38000545.
726     LOG(ERROR) << "Test skipped because it's running as root";
727     return;
728   }
729 
730   std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
731 
732   // We create a dex, generate an oat for it, then overwrite the dex with a
733   // different dex to make the oat out of date.
734   Copy(GetDexSrc1(), dex_location);
735   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
736   Copy(GetDexSrc2(), dex_location);
737 
738   ScopedNonWritable scoped_non_writable(dex_location);
739   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
740 
741   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
742   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
743       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
744   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
745       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
746 
747   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
748   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
749   EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
750   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
751 }
752 
753 // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
754 // to the dex checksum, but no ODEX file.
TEST_F(OatFileAssistantTest,VdexDexOutOfDate)755 TEST_F(OatFileAssistantTest, VdexDexOutOfDate) {
756   std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar";
757   std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat";
758 
759   Copy(GetDexSrc1(), dex_location);
760   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
761   ASSERT_EQ(0, unlink(odex_location.c_str()));
762   Copy(GetDexSrc2(), dex_location);
763 
764   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
765 
766   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
767       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
768 }
769 
770 // Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry
771 // is out of date and there is no corresponding ODEX file.
TEST_F(OatFileAssistantTest,VdexMultiDexNonMainOutOfDate)772 TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
773   std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar";
774   std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex";
775 
776   Copy(GetMultiDexSrc1(), dex_location);
777   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
778   ASSERT_EQ(0, unlink(odex_location.c_str()));
779   Copy(GetMultiDexSrc2(), dex_location);
780 
781   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
782 
783   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
784       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
785 }
786 
787 // Case: We have a DEX file and an OAT file out of date with respect to the
788 // boot image.
TEST_F(OatFileAssistantTest,OatImageOutOfDate)789 TEST_F(OatFileAssistantTest, OatImageOutOfDate) {
790   if (IsExecutedAsRoot()) {
791     // We cannot simulate non writable locations when executed as root: b/38000545.
792     LOG(ERROR) << "Test skipped because it's running as root";
793     return;
794   }
795 
796   std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
797 
798   Copy(GetDexSrc1(), dex_location);
799   GenerateOatForTest(dex_location.c_str(),
800                      CompilerFilter::kSpeed,
801                      /* with_alternate_image= */ true);
802 
803   ScopedNonWritable scoped_non_writable(dex_location);
804   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
805 
806   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
807   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
808       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
809   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
810       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
811   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
812       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
813 
814   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
815   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
816   EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
817   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
818 }
819 
820 // Case: We have a DEX file and a verify-at-runtime OAT file out of date with
821 // respect to the boot image.
822 // It shouldn't matter that the OAT file is out of date, because it is
823 // verify-at-runtime.
TEST_F(OatFileAssistantTest,OatVerifyAtRuntimeImageOutOfDate)824 TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) {
825   if (IsExecutedAsRoot()) {
826     // We cannot simulate non writable locations when executed as root: b/38000545.
827     LOG(ERROR) << "Test skipped because it's running as root";
828     return;
829   }
830 
831   std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar";
832 
833   Copy(GetDexSrc1(), dex_location);
834   GenerateOatForTest(dex_location.c_str(),
835                      CompilerFilter::kExtract,
836                      /* with_alternate_image= */ true);
837 
838   ScopedNonWritable scoped_non_writable(dex_location);
839   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
840 
841   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
842   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
843       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
844   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
845       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
846 
847   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
848   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
849   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
850   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
851 }
852 
853 // Case: We have a DEX file and an ODEX file, but no OAT file.
TEST_F(OatFileAssistantTest,DexOdexNoOat)854 TEST_F(OatFileAssistantTest, DexOdexNoOat) {
855   std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
856   std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
857 
858   // Create the dex and odex files
859   Copy(GetDexSrc1(), dex_location);
860   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
861 
862   // Verify the status.
863   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
864 
865   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
866       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
867   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
868       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
869 
870   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
871   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
872   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
873   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
874 
875   // We should still be able to get the non-executable odex file to run from.
876   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
877   ASSERT_TRUE(oat_file.get() != nullptr);
878 }
879 
880 // Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file.
TEST_F(OatFileAssistantTest,StrippedDexOdexNoOat)881 TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
882   std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
883   std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
884 
885   // Create the dex and odex files
886   Copy(GetDexSrc1(), dex_location);
887   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
888 
889   // Strip the dex file
890   Copy(GetStrippedDexSrc1(), dex_location);
891 
892   // Verify the status.
893   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
894 
895   EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
896       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
897 
898   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
899   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
900   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
901   EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
902 
903   // Verify we can load the dex files from it.
904   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
905   ASSERT_TRUE(oat_file.get() != nullptr);
906   EXPECT_TRUE(oat_file->IsExecutable());
907   std::vector<std::unique_ptr<const DexFile>> dex_files;
908   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
909   EXPECT_EQ(1u, dex_files.size());
910 }
911 
912 // Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file.
TEST_F(OatFileAssistantTest,StrippedDexOdexOat)913 TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
914   std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
915   std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
916 
917   // Create the oat file from a different dex file so it looks out of date.
918   Copy(GetDexSrc2(), dex_location);
919   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
920 
921   // Create the odex file
922   Copy(GetDexSrc1(), dex_location);
923   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
924 
925   // Strip the dex file.
926   Copy(GetStrippedDexSrc1(), dex_location);
927 
928   // Verify the status.
929   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
930 
931   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
932       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
933   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
934       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
935   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,  // Compiling from the .vdex file
936       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
937 
938   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
939   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
940   EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
941   EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
942 
943   // Verify we can load the dex files from it.
944   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
945   ASSERT_TRUE(oat_file.get() != nullptr);
946   EXPECT_TRUE(oat_file->IsExecutable());
947   std::vector<std::unique_ptr<const DexFile>> dex_files;
948   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
949   EXPECT_EQ(1u, dex_files.size());
950 }
951 
952 // Case: We have a stripped (or resource-only) DEX file, no ODEX file and no
953 // OAT file. Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,ResourceOnlyDex)954 TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
955   std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
956 
957   Copy(GetStrippedDexSrc1(), dex_location);
958 
959   // Verify the status.
960   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
961 
962   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
963       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
964   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
965       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
966   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
967       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
968 
969   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
970   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
971   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
972   EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
973 
974   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
975       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
976 
977   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
978   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
979   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
980   EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
981 }
982 
983 // Case: We have a DEX file, an ODEX file and an OAT file.
984 // Expect: It shouldn't crash. We should load the odex file executable.
TEST_F(OatFileAssistantTest,OdexOatOverlap)985 TEST_F(OatFileAssistantTest, OdexOatOverlap) {
986   std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
987   std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
988 
989   // Create the dex, the odex and the oat files.
990   Copy(GetDexSrc1(), dex_location);
991   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
992   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
993 
994   // Verify things don't go bad.
995   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
996 
997   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
998             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
999 
1000   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1001   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
1002   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
1003   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
1004 
1005   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1006   ASSERT_TRUE(oat_file.get() != nullptr);
1007 
1008   EXPECT_TRUE(oat_file->IsExecutable());
1009   std::vector<std::unique_ptr<const DexFile>> dex_files;
1010   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1011   EXPECT_EQ(1u, dex_files.size());
1012 }
1013 
1014 // Case: We have a DEX file and a VerifyAtRuntime ODEX file, but no OAT file.
1015 // Expect: The status is kNoDexOptNeeded, because VerifyAtRuntime contains no code.
TEST_F(OatFileAssistantTest,DexVerifyAtRuntimeOdexNoOat)1016 TEST_F(OatFileAssistantTest, DexVerifyAtRuntimeOdexNoOat) {
1017   std::string dex_location = GetScratchDir() + "/DexVerifyAtRuntimeOdexNoOat.jar";
1018   std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex";
1019 
1020   // Create the dex and odex files
1021   Copy(GetDexSrc1(), dex_location);
1022   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
1023 
1024   // Verify the status.
1025   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1026 
1027   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1028       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
1029   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
1030       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
1031 
1032   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1033   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
1034   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1035   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
1036 }
1037 
1038 // Case: We have a DEX file and up-to-date OAT file for it.
1039 // Expect: We should load an executable dex file.
TEST_F(OatFileAssistantTest,LoadOatUpToDate)1040 TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
1041   if (IsExecutedAsRoot()) {
1042     // We cannot simulate non writable locations when executed as root: b/38000545.
1043     LOG(ERROR) << "Test skipped because it's running as root";
1044     return;
1045   }
1046 
1047   std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
1048 
1049   Copy(GetDexSrc1(), dex_location);
1050   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1051 
1052   ScopedNonWritable scoped_non_writable(dex_location);
1053   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1054 
1055   // Load the oat using an oat file assistant.
1056   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1057 
1058   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1059   ASSERT_TRUE(oat_file.get() != nullptr);
1060   EXPECT_TRUE(oat_file->IsExecutable());
1061   std::vector<std::unique_ptr<const DexFile>> dex_files;
1062   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1063   EXPECT_EQ(1u, dex_files.size());
1064 }
1065 
1066 // Case: We have a DEX file and up-to-date quicken OAT file for it.
1067 // Expect: We should still load the oat file as executable.
TEST_F(OatFileAssistantTest,LoadExecInterpretOnlyOatUpToDate)1068 TEST_F(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) {
1069   if (IsExecutedAsRoot()) {
1070     // We cannot simulate non writable locations when executed as root: b/38000545.
1071     LOG(ERROR) << "Test skipped because it's running as root";
1072     return;
1073   }
1074 
1075   std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar";
1076 
1077   Copy(GetDexSrc1(), dex_location);
1078   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken);
1079 
1080   ScopedNonWritable scoped_non_writable(dex_location);
1081   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1082 
1083   // Load the oat using an oat file assistant.
1084   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1085 
1086   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1087   ASSERT_TRUE(oat_file.get() != nullptr);
1088   EXPECT_TRUE(oat_file->IsExecutable());
1089   std::vector<std::unique_ptr<const DexFile>> dex_files;
1090   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1091   EXPECT_EQ(1u, dex_files.size());
1092 }
1093 
1094 // Case: We have a DEX file and up-to-date OAT file for it.
1095 // Expect: Loading non-executable should load the oat non-executable.
TEST_F(OatFileAssistantTest,LoadNoExecOatUpToDate)1096 TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) {
1097   if (IsExecutedAsRoot()) {
1098     // We cannot simulate non writable locations when executed as root: b/38000545.
1099     LOG(ERROR) << "Test skipped because it's running as root";
1100     return;
1101   }
1102 
1103   std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
1104 
1105   Copy(GetDexSrc1(), dex_location);
1106 
1107   ScopedNonWritable scoped_non_writable(dex_location);
1108   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1109 
1110   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1111 
1112   // Load the oat using an oat file assistant.
1113   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1114 
1115   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1116   ASSERT_TRUE(oat_file.get() != nullptr);
1117   EXPECT_FALSE(oat_file->IsExecutable());
1118   std::vector<std::unique_ptr<const DexFile>> dex_files;
1119   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1120   EXPECT_EQ(1u, dex_files.size());
1121 }
1122 
1123 // Turn an absolute path into a path relative to the current working
1124 // directory.
MakePathRelative(const std::string & target)1125 static std::string MakePathRelative(const std::string& target) {
1126   char buf[MAXPATHLEN];
1127   std::string cwd = getcwd(buf, MAXPATHLEN);
1128 
1129   // Split the target and cwd paths into components.
1130   std::vector<std::string> target_path;
1131   std::vector<std::string> cwd_path;
1132   Split(target, '/', &target_path);
1133   Split(cwd, '/', &cwd_path);
1134 
1135   // Reverse the path components, so we can use pop_back().
1136   std::reverse(target_path.begin(), target_path.end());
1137   std::reverse(cwd_path.begin(), cwd_path.end());
1138 
1139   // Drop the common prefix of the paths. Because we reversed the path
1140   // components, this becomes the common suffix of target_path and cwd_path.
1141   while (!target_path.empty() && !cwd_path.empty()
1142       && target_path.back() == cwd_path.back()) {
1143     target_path.pop_back();
1144     cwd_path.pop_back();
1145   }
1146 
1147   // For each element of the remaining cwd_path, add '..' to the beginning
1148   // of the target path. Because we reversed the path components, we add to
1149   // the end of target_path.
1150   for (unsigned int i = 0; i < cwd_path.size(); i++) {
1151     target_path.push_back("..");
1152   }
1153 
1154   // Reverse again to get the right path order, and join to get the result.
1155   std::reverse(target_path.begin(), target_path.end());
1156   return android::base::Join(target_path, '/');
1157 }
1158 
1159 // Case: Non-absolute path to Dex location.
1160 // Expect: Not sure, but it shouldn't crash.
TEST_F(OatFileAssistantTest,NonAbsoluteDexLocation)1161 TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
1162   std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar";
1163   Copy(GetDexSrc1(), abs_dex_location);
1164 
1165   std::string dex_location = MakePathRelative(abs_dex_location);
1166   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1167 
1168   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1169   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1170       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
1171   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1172   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1173 }
1174 
1175 // Case: Very short, non-existent Dex location.
1176 // Expect: kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,ShortDexLocation)1177 TEST_F(OatFileAssistantTest, ShortDexLocation) {
1178   std::string dex_location = "/xx";
1179 
1180   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1181 
1182   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1183   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1184       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
1185   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1186   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1187   EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
1188 }
1189 
1190 // Case: Non-standard extension for dex file.
1191 // Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest,LongDexExtension)1192 TEST_F(OatFileAssistantTest, LongDexExtension) {
1193   std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
1194   Copy(GetDexSrc1(), dex_location);
1195 
1196   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1197 
1198   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1199       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
1200 
1201   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1202   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1203   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1204 }
1205 
1206 // A task to generate a dex location. Used by the RaceToGenerate test.
1207 class RaceGenerateTask : public Task {
1208  public:
RaceGenerateTask(OatFileAssistantTest & test,const std::string & dex_location,const std::string & oat_location,Mutex * lock)1209   RaceGenerateTask(OatFileAssistantTest& test,
1210                    const std::string& dex_location,
1211                    const std::string& oat_location,
1212                    Mutex* lock)
1213       : test_(test),
1214         dex_location_(dex_location),
1215         oat_location_(oat_location),
1216         lock_(lock),
1217         loaded_oat_file_(nullptr)
1218   {}
1219 
Run(Thread * self ATTRIBUTE_UNUSED)1220   void Run(Thread* self ATTRIBUTE_UNUSED) override {
1221     // Load the dex files, and save a pointer to the loaded oat file, so that
1222     // we can verify only one oat file was loaded for the dex location.
1223     std::vector<std::unique_ptr<const DexFile>> dex_files;
1224     std::vector<std::string> error_msgs;
1225     const OatFile* oat_file = nullptr;
1226     {
1227       MutexLock mu(Thread::Current(), *lock_);
1228       // Create the oat file.
1229       std::vector<std::string> args;
1230       args.push_back("--dex-file=" + dex_location_);
1231       args.push_back("--oat-file=" + oat_location_);
1232       std::string error_msg;
1233       ASSERT_TRUE(test_.Dex2Oat(args, &error_msg)) << error_msg;
1234     }
1235 
1236     dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1237         dex_location_.c_str(),
1238         Runtime::Current()->GetSystemClassLoader(),
1239         /*dex_elements=*/nullptr,
1240         &oat_file,
1241         &error_msgs);
1242     CHECK(!dex_files.empty()) << android::base::Join(error_msgs, '\n');
1243     if (dex_files[0]->GetOatDexFile() != nullptr) {
1244       loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile();
1245     }
1246     CHECK_EQ(loaded_oat_file_, oat_file);
1247   }
1248 
GetLoadedOatFile() const1249   const OatFile* GetLoadedOatFile() const {
1250     return loaded_oat_file_;
1251   }
1252 
1253  private:
1254   OatFileAssistantTest& test_;
1255   std::string dex_location_;
1256   std::string oat_location_;
1257   Mutex* lock_;
1258   const OatFile* loaded_oat_file_;
1259 };
1260 
1261 // Test the case where dex2oat invocations race with multiple processes trying to
1262 // load the oat file.
TEST_F(OatFileAssistantTest,RaceToGenerate)1263 TEST_F(OatFileAssistantTest, RaceToGenerate) {
1264   std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
1265   std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat";
1266 
1267   // Start the runtime to initialize the system's class loader.
1268   Thread::Current()->TransitionFromSuspendedToRunnable();
1269   runtime_->Start();
1270 
1271   // We use the lib core dex file, because it's large, and hopefully should
1272   // take a while to generate.
1273   Copy(GetLibCoreDexFileNames()[0], dex_location);
1274 
1275   const size_t kNumThreads = 32;
1276   Thread* self = Thread::Current();
1277   ThreadPool thread_pool("Oat file assistant test thread pool", kNumThreads);
1278   std::vector<std::unique_ptr<RaceGenerateTask>> tasks;
1279   Mutex lock("RaceToGenerate");
1280   for (size_t i = 0; i < kNumThreads; i++) {
1281     std::unique_ptr<RaceGenerateTask> task(
1282         new RaceGenerateTask(*this, dex_location, oat_location, &lock));
1283     thread_pool.AddTask(self, task.get());
1284     tasks.push_back(std::move(task));
1285   }
1286   thread_pool.StartWorkers(self);
1287   thread_pool.Wait(self, /* do_work= */ true, /* may_hold_locks= */ false);
1288 
1289   // Verify that tasks which got an oat file got a unique one.
1290   std::set<const OatFile*> oat_files;
1291   for (auto& task : tasks) {
1292     const OatFile* oat_file = task->GetLoadedOatFile();
1293     if (oat_file != nullptr) {
1294       EXPECT_TRUE(oat_files.find(oat_file) == oat_files.end());
1295       oat_files.insert(oat_file);
1296     }
1297   }
1298 }
1299 
1300 // Case: We have a DEX file and an ODEX file, and no OAT file,
1301 // Expect: We should load the odex file executable.
TEST_F(DexoptTest,LoadDexOdexNoOat)1302 TEST_F(DexoptTest, LoadDexOdexNoOat) {
1303   std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
1304   std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
1305 
1306   // Create the dex and odex files
1307   Copy(GetDexSrc1(), dex_location);
1308   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1309 
1310   // Load the oat using an executable oat file assistant.
1311   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1312 
1313   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1314   ASSERT_TRUE(oat_file.get() != nullptr);
1315   EXPECT_TRUE(oat_file->IsExecutable());
1316   std::vector<std::unique_ptr<const DexFile>> dex_files;
1317   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1318   EXPECT_EQ(1u, dex_files.size());
1319 }
1320 
1321 // Case: We have a MultiDEX file and an ODEX file, and no OAT file.
1322 // Expect: We should load the odex file executable.
TEST_F(DexoptTest,LoadMultiDexOdexNoOat)1323 TEST_F(DexoptTest, LoadMultiDexOdexNoOat) {
1324   std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
1325   std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
1326 
1327   // Create the dex and odex files
1328   Copy(GetMultiDexSrc1(), dex_location);
1329   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1330 
1331   // Load the oat using an executable oat file assistant.
1332   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1333 
1334   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1335   ASSERT_TRUE(oat_file.get() != nullptr);
1336   EXPECT_TRUE(oat_file->IsExecutable());
1337   std::vector<std::unique_ptr<const DexFile>> dex_files;
1338   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1339   EXPECT_EQ(2u, dex_files.size());
1340 }
1341 
TEST(OatFileAssistantUtilsTest,DexLocationToOdexFilename)1342 TEST(OatFileAssistantUtilsTest, DexLocationToOdexFilename) {
1343   std::string error_msg;
1344   std::string odex_file;
1345 
1346   EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1347         "/foo/bar/baz.jar", InstructionSet::kArm, &odex_file, &error_msg)) << error_msg;
1348   EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1349 
1350   EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1351         "/foo/bar/baz.funnyext", InstructionSet::kArm, &odex_file, &error_msg)) << error_msg;
1352   EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1353 
1354   EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename(
1355         "nopath.jar", InstructionSet::kArm, &odex_file, &error_msg));
1356   EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename(
1357         "/foo/bar/baz_noext", InstructionSet::kArm, &odex_file, &error_msg));
1358 }
1359 
1360 // Verify the dexopt status values from dalvik.system.DexFile
1361 // match the OatFileAssistant::DexOptStatus values.
TEST_F(OatFileAssistantTest,DexOptStatusValues)1362 TEST_F(OatFileAssistantTest, DexOptStatusValues) {
1363   std::pair<OatFileAssistant::DexOptNeeded, const char*> mapping[] = {
1364     {OatFileAssistant::kNoDexOptNeeded, "NO_DEXOPT_NEEDED"},
1365     {OatFileAssistant::kDex2OatFromScratch, "DEX2OAT_FROM_SCRATCH"},
1366     {OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"},
1367     {OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"},
1368   };
1369 
1370   ScopedObjectAccess soa(Thread::Current());
1371   StackHandleScope<1> hs(soa.Self());
1372   ClassLinker* linker = Runtime::Current()->GetClassLinker();
1373   Handle<mirror::Class> dexfile(
1374       hs.NewHandle(linker->FindSystemClass(soa.Self(), "Ldalvik/system/DexFile;")));
1375   ASSERT_FALSE(dexfile == nullptr);
1376   linker->EnsureInitialized(soa.Self(), dexfile, true, true);
1377 
1378   for (std::pair<OatFileAssistant::DexOptNeeded, const char*> field : mapping) {
1379     ArtField* art_field = mirror::Class::FindStaticField(
1380         soa.Self(), dexfile.Get(), field.second, "I");
1381     ASSERT_FALSE(art_field == nullptr);
1382     EXPECT_EQ(art_field->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
1383     EXPECT_EQ(field.first, art_field->GetInt(dexfile.Get()));
1384   }
1385 }
1386 
TEST_F(OatFileAssistantTest,GetDexOptNeededWithOutOfDateContext)1387 TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) {
1388   std::string dex_location = GetScratchDir() + "/TestDex.jar";
1389   std::string odex_location = GetOdexDir() + "/TestDex.odex";
1390 
1391   std::string context_location = GetScratchDir() + "/ContextDex.jar";
1392   Copy(GetDexSrc1(), dex_location);
1393   Copy(GetDexSrc2(), context_location);
1394 
1395   std::string context_str = "PCL[" + context_location + "]";
1396 
1397   std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
1398   ASSERT_TRUE(context != nullptr);
1399   ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, ""));
1400 
1401   std::string error_msg;
1402   std::vector<std::string> args;
1403   args.push_back("--dex-file=" + dex_location);
1404   args.push_back("--oat-file=" + odex_location);
1405   args.push_back("--class-loader-context=" + context_str);
1406   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
1407 
1408   // Update the context by overriding the jar file.
1409   Copy(GetMultiDexSrc2(), context_location);
1410 
1411   {
1412     std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
1413     ASSERT_TRUE(updated_context != nullptr);
1414     OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1415     // DexOptNeeded should advise compilation from scratch when the context changes.
1416     EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1417               GetDexOptNeeded(&oat_file_assistant,
1418                     CompilerFilter::kDefaultCompilerFilter,
1419                     updated_context));
1420   }
1421   {
1422     std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
1423     ASSERT_TRUE(updated_context != nullptr);
1424     OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1425     // Now check that DexOptNeeded does not advise compilation if we only extracted the file.
1426     args.push_back("--compiler-filter=extract");
1427     ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
1428     EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1429               GetDexOptNeeded(&oat_file_assistant,
1430                     CompilerFilter::kExtract,
1431                     updated_context));
1432   }
1433 }
1434 
1435 // Test that GetLocation of a dex file is the same whether the dex
1436 // filed is backed by an oat file or not.
TEST_F(OatFileAssistantTest,GetDexLocation)1437 TEST_F(OatFileAssistantTest, GetDexLocation) {
1438   std::string dex_location = GetScratchDir() + "/TestDex.jar";
1439   std::string oat_location = GetOdexDir() + "/TestDex.odex";
1440 
1441   // Start the runtime to initialize the system's class loader.
1442   Thread::Current()->TransitionFromSuspendedToRunnable();
1443   runtime_->Start();
1444 
1445   Copy(GetDexSrc1(), dex_location);
1446 
1447   std::vector<std::unique_ptr<const DexFile>> dex_files;
1448   std::vector<std::string> error_msgs;
1449   const OatFile* oat_file = nullptr;
1450 
1451   dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1452       dex_location.c_str(),
1453       Runtime::Current()->GetSystemClassLoader(),
1454       /*dex_elements=*/nullptr,
1455       &oat_file,
1456       &error_msgs);
1457   ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
1458   EXPECT_EQ(oat_file, nullptr);
1459   std::string stored_dex_location = dex_files[0]->GetLocation();
1460   {
1461     // Create the oat file.
1462     std::vector<std::string> args;
1463     args.push_back("--dex-file=" + dex_location);
1464     args.push_back("--dex-location=TestDex.jar");
1465     args.push_back("--oat-file=" + oat_location);
1466     std::string error_msg;
1467     ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
1468   }
1469   dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1470       dex_location.c_str(),
1471       Runtime::Current()->GetSystemClassLoader(),
1472       /*dex_elements=*/nullptr,
1473       &oat_file,
1474       &error_msgs);
1475   ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
1476   ASSERT_NE(oat_file, nullptr);
1477   std::string oat_stored_dex_location = dex_files[0]->GetLocation();
1478   EXPECT_EQ(oat_stored_dex_location, stored_dex_location);
1479 }
1480 
1481 // Test that a dex file on the platform location gets the right hiddenapi domain,
1482 // regardless of whether it has a backing oat file.
TEST_F(OatFileAssistantTest,SystemFrameworkDir)1483 TEST_F(OatFileAssistantTest, SystemFrameworkDir) {
1484   std::string filebase = "OatFileAssistantTestSystemFrameworkDir";
1485   std::string dex_location = GetAndroidRoot() + "/framework/" + filebase + ".jar";
1486   Copy(GetDexSrc1(), dex_location);
1487 
1488   std::string odex_dir = GetAndroidRoot() + "/framework/oat/";
1489   mkdir(odex_dir.c_str(), 0700);
1490   odex_dir = odex_dir + std::string(GetInstructionSetString(kRuntimeISA));
1491   mkdir(odex_dir.c_str(), 0700);
1492   std::string oat_location = odex_dir + "/" + filebase + ".odex";
1493   // Clean up in case previous run crashed.
1494   remove(oat_location.c_str());
1495 
1496   // Start the runtime to initialize the system's class loader.
1497   Thread::Current()->TransitionFromSuspendedToRunnable();
1498   runtime_->Start();
1499 
1500   std::vector<std::unique_ptr<const DexFile>> dex_files_first;
1501   std::vector<std::unique_ptr<const DexFile>> dex_files_second;
1502   std::vector<std::string> error_msgs;
1503   const OatFile* oat_file = nullptr;
1504 
1505   dex_files_first = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1506       dex_location.c_str(),
1507       Runtime::Current()->GetSystemClassLoader(),
1508       /*dex_elements=*/nullptr,
1509       &oat_file,
1510       &error_msgs);
1511   ASSERT_EQ(dex_files_first.size(), 1u) << android::base::Join(error_msgs, "\n");
1512   EXPECT_EQ(oat_file, nullptr) << dex_location;
1513   EXPECT_EQ(dex_files_first[0]->GetOatDexFile(), nullptr);
1514 
1515   // Register the dex file to get a domain.
1516   {
1517     ScopedObjectAccess soa(Thread::Current());
1518     Runtime::Current()->GetClassLinker()->RegisterDexFile(
1519         *dex_files_first[0],
1520         soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader()));
1521   }
1522   std::string stored_dex_location = dex_files_first[0]->GetLocation();
1523   EXPECT_EQ(dex_files_first[0]->GetHiddenapiDomain(), hiddenapi::Domain::kPlatform);
1524   {
1525     // Create the oat file.
1526     std::vector<std::string> args;
1527     args.push_back("--dex-file=" + dex_location);
1528     args.push_back("--dex-location=" + filebase + ".jar");
1529     args.push_back("--oat-file=" + oat_location);
1530     std::string error_msg;
1531     ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
1532   }
1533   dex_files_second = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1534       dex_location.c_str(),
1535       Runtime::Current()->GetSystemClassLoader(),
1536       /*dex_elements=*/nullptr,
1537       &oat_file,
1538       &error_msgs);
1539   ASSERT_EQ(dex_files_second.size(), 1u) << android::base::Join(error_msgs, "\n");
1540   ASSERT_NE(oat_file, nullptr);
1541   EXPECT_NE(dex_files_second[0]->GetOatDexFile(), nullptr);
1542   EXPECT_NE(dex_files_second[0]->GetOatDexFile()->GetOatFile(), nullptr);
1543 
1544   // Register the dex file to get a domain.
1545   {
1546     ScopedObjectAccess soa(Thread::Current());
1547     Runtime::Current()->GetClassLinker()->RegisterDexFile(
1548         *dex_files_second[0],
1549         soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader()));
1550   }
1551   std::string oat_stored_dex_location = dex_files_second[0]->GetLocation();
1552   EXPECT_EQ(oat_stored_dex_location, stored_dex_location);
1553   EXPECT_EQ(dex_files_second[0]->GetHiddenapiDomain(), hiddenapi::Domain::kPlatform);
1554   EXPECT_EQ(0, remove(oat_location.c_str()));
1555 }
1556 
1557 // TODO: More Tests:
1558 //  * Test class linker falls back to unquickened dex for DexNoOat
1559 //  * Test class linker falls back to unquickened dex for MultiDexNoOat
1560 //  * Test using secondary isa
1561 //  * Test for status of oat while oat is being generated (how?)
1562 //  * Test case where 32 and 64 bit boot class paths differ,
1563 //      and we ask IsInBootClassPath for a class in exactly one of the 32 or
1564 //      64 bit boot class paths.
1565 //  * Test unexpected scenarios (?):
1566 //    - Dex is stripped, don't have odex.
1567 //    - Oat file corrupted after status check, before reload unexecutable
1568 //    because it's unrelocated and no dex2oat
1569 }  // namespace art
1570