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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
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.HasDexFiles());
688 }
689 
690 // Case: We have a DEX file and an OAT file out of date with respect to the
691 // dex checksum.
TEST_F(OatFileAssistantTest,OatDexOutOfDate)692 TEST_F(OatFileAssistantTest, OatDexOutOfDate) {
693   if (IsExecutedAsRoot()) {
694     // We cannot simulate non writable locations when executed as root: b/38000545.
695     LOG(ERROR) << "Test skipped because it's running as root";
696     return;
697   }
698 
699   std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
700 
701   // We create a dex, generate an oat for it, then overwrite the dex with a
702   // different dex to make the oat out of date.
703   Copy(GetDexSrc1(), dex_location);
704   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
705   Copy(GetDexSrc2(), dex_location);
706 
707   ScopedNonWritable scoped_non_writable(dex_location);
708   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
709 
710   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
711   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
712       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
713   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
714       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
715 
716   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
717   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
718   EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
719   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
720 }
721 
722 // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
723 // to the dex checksum, but no ODEX file.
TEST_F(OatFileAssistantTest,VdexDexOutOfDate)724 TEST_F(OatFileAssistantTest, VdexDexOutOfDate) {
725   std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar";
726   std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat";
727 
728   Copy(GetDexSrc1(), dex_location);
729   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
730   ASSERT_EQ(0, unlink(odex_location.c_str()));
731   Copy(GetDexSrc2(), dex_location);
732 
733   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
734 
735   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
736       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
737 }
738 
739 // Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry
740 // is out of date and there is no corresponding ODEX file.
TEST_F(OatFileAssistantTest,VdexMultiDexNonMainOutOfDate)741 TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
742   std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar";
743   std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex";
744 
745   Copy(GetMultiDexSrc1(), dex_location);
746   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
747   ASSERT_EQ(0, unlink(odex_location.c_str()));
748   Copy(GetMultiDexSrc2(), dex_location);
749 
750   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
751 
752   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
753       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
754 }
755 
756 // Case: We have a DEX file and an OAT file out of date with respect to the
757 // boot image.
TEST_F(OatFileAssistantTest,OatImageOutOfDate)758 TEST_F(OatFileAssistantTest, OatImageOutOfDate) {
759   if (IsExecutedAsRoot()) {
760     // We cannot simulate non writable locations when executed as root: b/38000545.
761     LOG(ERROR) << "Test skipped because it's running as root";
762     return;
763   }
764 
765   std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
766 
767   Copy(GetDexSrc1(), dex_location);
768   GenerateOatForTest(dex_location.c_str(),
769                      CompilerFilter::kSpeed,
770                      /* with_alternate_image= */ true);
771 
772   ScopedNonWritable scoped_non_writable(dex_location);
773   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
774 
775   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
776   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
777       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
778   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
779       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
780   EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
781       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
782 
783   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
784   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
785   EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
786   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
787 }
788 
789 // Case: We have a DEX file and a verify-at-runtime OAT file out of date with
790 // respect to the boot image.
791 // It shouldn't matter that the OAT file is out of date, because it is
792 // verify-at-runtime.
TEST_F(OatFileAssistantTest,OatVerifyAtRuntimeImageOutOfDate)793 TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) {
794   if (IsExecutedAsRoot()) {
795     // We cannot simulate non writable locations when executed as root: b/38000545.
796     LOG(ERROR) << "Test skipped because it's running as root";
797     return;
798   }
799 
800   std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar";
801 
802   Copy(GetDexSrc1(), dex_location);
803   GenerateOatForTest(dex_location.c_str(),
804                      CompilerFilter::kExtract,
805                      /* with_alternate_image= */ true);
806 
807   ScopedNonWritable scoped_non_writable(dex_location);
808   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
809 
810   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
811   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
812       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
813   EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
814       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
815 
816   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
817   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
818   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
819   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
820 }
821 
822 // Case: We have a DEX file and an ODEX file, but no OAT file.
TEST_F(OatFileAssistantTest,DexOdexNoOat)823 TEST_F(OatFileAssistantTest, DexOdexNoOat) {
824   std::string dex_location = GetScratchDir() + "/DexOdexNoOat.jar";
825   std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
826 
827   // Create the dex and odex files
828   Copy(GetDexSrc1(), dex_location);
829   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
830 
831   // Verify the status.
832   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
833 
834   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
835       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
836   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
837       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
838 
839   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
840   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
841   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
842   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
843 
844   // We should still be able to get the non-executable odex file to run from.
845   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
846   ASSERT_TRUE(oat_file.get() != nullptr);
847 }
848 
849 // Case: We have a resource-only DEX file, no ODEX file and no
850 // OAT file. Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,ResourceOnlyDex)851 TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
852   std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
853 
854   Copy(GetStrippedDexSrc1(), dex_location);
855 
856   // Verify the status.
857   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
858 
859   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
860       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
861   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
862       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
863   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
864       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken));
865 
866   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
867   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
868   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
869   EXPECT_FALSE(oat_file_assistant.HasDexFiles());
870 
871   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
872       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
873 
874   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
875   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
876   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
877   EXPECT_FALSE(oat_file_assistant.HasDexFiles());
878 }
879 
880 // Case: We have a DEX file, an ODEX file and an OAT file.
881 // Expect: It shouldn't crash. We should load the odex file executable.
TEST_F(OatFileAssistantTest,OdexOatOverlap)882 TEST_F(OatFileAssistantTest, OdexOatOverlap) {
883   std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
884   std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
885 
886   // Create the dex, the odex and the oat files.
887   Copy(GetDexSrc1(), dex_location);
888   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
889   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
890 
891   // Verify things don't go bad.
892   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
893 
894   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
895             GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
896 
897   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
898   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
899   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
900   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
901 
902   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
903   ASSERT_TRUE(oat_file.get() != nullptr);
904 
905   EXPECT_TRUE(oat_file->IsExecutable());
906   std::vector<std::unique_ptr<const DexFile>> dex_files;
907   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
908   EXPECT_EQ(1u, dex_files.size());
909 }
910 
911 // Case: We have a DEX file and a VerifyAtRuntime ODEX file, but no OAT file.
912 // Expect: The status is kNoDexOptNeeded, because VerifyAtRuntime contains no code.
TEST_F(OatFileAssistantTest,DexVerifyAtRuntimeOdexNoOat)913 TEST_F(OatFileAssistantTest, DexVerifyAtRuntimeOdexNoOat) {
914   std::string dex_location = GetScratchDir() + "/DexVerifyAtRuntimeOdexNoOat.jar";
915   std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex";
916 
917   // Create the dex and odex files
918   Copy(GetDexSrc1(), dex_location);
919   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
920 
921   // Verify the status.
922   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
923 
924   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
925       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
926   EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
927       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
928 
929   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
930   EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
931   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
932   EXPECT_TRUE(oat_file_assistant.HasDexFiles());
933 }
934 
935 // Case: We have a DEX file and up-to-date OAT file for it.
936 // Expect: We should load an executable dex file.
TEST_F(OatFileAssistantTest,LoadOatUpToDate)937 TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
938   if (IsExecutedAsRoot()) {
939     // We cannot simulate non writable locations when executed as root: b/38000545.
940     LOG(ERROR) << "Test skipped because it's running as root";
941     return;
942   }
943 
944   std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
945 
946   Copy(GetDexSrc1(), dex_location);
947   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
948 
949   ScopedNonWritable scoped_non_writable(dex_location);
950   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
951 
952   // Load the oat using an oat file assistant.
953   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
954 
955   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
956   ASSERT_TRUE(oat_file.get() != nullptr);
957   EXPECT_TRUE(oat_file->IsExecutable());
958   std::vector<std::unique_ptr<const DexFile>> dex_files;
959   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
960   EXPECT_EQ(1u, dex_files.size());
961 }
962 
963 // Case: We have a DEX file and up-to-date quicken OAT file for it.
964 // Expect: We should still load the oat file as executable.
TEST_F(OatFileAssistantTest,LoadExecInterpretOnlyOatUpToDate)965 TEST_F(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) {
966   if (IsExecutedAsRoot()) {
967     // We cannot simulate non writable locations when executed as root: b/38000545.
968     LOG(ERROR) << "Test skipped because it's running as root";
969     return;
970   }
971 
972   std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar";
973 
974   Copy(GetDexSrc1(), dex_location);
975   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken);
976 
977   ScopedNonWritable scoped_non_writable(dex_location);
978   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
979 
980   // Load the oat using an oat file assistant.
981   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
982 
983   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
984   ASSERT_TRUE(oat_file.get() != nullptr);
985   EXPECT_TRUE(oat_file->IsExecutable());
986   std::vector<std::unique_ptr<const DexFile>> dex_files;
987   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
988   EXPECT_EQ(1u, dex_files.size());
989 }
990 
991 // Case: We have a DEX file and up-to-date OAT file for it.
992 // Expect: Loading non-executable should load the oat non-executable.
TEST_F(OatFileAssistantTest,LoadNoExecOatUpToDate)993 TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) {
994   if (IsExecutedAsRoot()) {
995     // We cannot simulate non writable locations when executed as root: b/38000545.
996     LOG(ERROR) << "Test skipped because it's running as root";
997     return;
998   }
999 
1000   std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
1001 
1002   Copy(GetDexSrc1(), dex_location);
1003 
1004   ScopedNonWritable scoped_non_writable(dex_location);
1005   ASSERT_TRUE(scoped_non_writable.IsSuccessful());
1006 
1007   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
1008 
1009   // Load the oat using an oat file assistant.
1010   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1011 
1012   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1013   ASSERT_TRUE(oat_file.get() != nullptr);
1014   EXPECT_FALSE(oat_file->IsExecutable());
1015   std::vector<std::unique_ptr<const DexFile>> dex_files;
1016   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1017   EXPECT_EQ(1u, dex_files.size());
1018 }
1019 
1020 // Turn an absolute path into a path relative to the current working
1021 // directory.
MakePathRelative(const std::string & target)1022 static std::string MakePathRelative(const std::string& target) {
1023   char buf[MAXPATHLEN];
1024   std::string cwd = getcwd(buf, MAXPATHLEN);
1025 
1026   // Split the target and cwd paths into components.
1027   std::vector<std::string> target_path;
1028   std::vector<std::string> cwd_path;
1029   Split(target, '/', &target_path);
1030   Split(cwd, '/', &cwd_path);
1031 
1032   // Reverse the path components, so we can use pop_back().
1033   std::reverse(target_path.begin(), target_path.end());
1034   std::reverse(cwd_path.begin(), cwd_path.end());
1035 
1036   // Drop the common prefix of the paths. Because we reversed the path
1037   // components, this becomes the common suffix of target_path and cwd_path.
1038   while (!target_path.empty() && !cwd_path.empty()
1039       && target_path.back() == cwd_path.back()) {
1040     target_path.pop_back();
1041     cwd_path.pop_back();
1042   }
1043 
1044   // For each element of the remaining cwd_path, add '..' to the beginning
1045   // of the target path. Because we reversed the path components, we add to
1046   // the end of target_path.
1047   for (unsigned int i = 0; i < cwd_path.size(); i++) {
1048     target_path.push_back("..");
1049   }
1050 
1051   // Reverse again to get the right path order, and join to get the result.
1052   std::reverse(target_path.begin(), target_path.end());
1053   return android::base::Join(target_path, '/');
1054 }
1055 
1056 // Case: Non-absolute path to Dex location.
1057 // Expect: Not sure, but it shouldn't crash.
TEST_F(OatFileAssistantTest,NonAbsoluteDexLocation)1058 TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
1059   std::string abs_dex_location = GetScratchDir() + "/NonAbsoluteDexLocation.jar";
1060   Copy(GetDexSrc1(), abs_dex_location);
1061 
1062   std::string dex_location = MakePathRelative(abs_dex_location);
1063   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1064 
1065   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1066   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1067       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
1068   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1069   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1070 }
1071 
1072 // Case: Very short, non-existent Dex location.
1073 // Expect: kNoDexOptNeeded.
TEST_F(OatFileAssistantTest,ShortDexLocation)1074 TEST_F(OatFileAssistantTest, ShortDexLocation) {
1075   std::string dex_location = "/xx";
1076 
1077   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1078 
1079   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1080   EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1081       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
1082   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1083   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1084   EXPECT_FALSE(oat_file_assistant.HasDexFiles());
1085 }
1086 
1087 // Case: Non-standard extension for dex file.
1088 // Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest,LongDexExtension)1089 TEST_F(OatFileAssistantTest, LongDexExtension) {
1090   std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
1091   Copy(GetDexSrc1(), dex_location);
1092 
1093   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1094 
1095   EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1096       GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
1097 
1098   EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
1099   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
1100   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
1101 }
1102 
1103 // A task to generate a dex location. Used by the RaceToGenerate test.
1104 class RaceGenerateTask : public Task {
1105  public:
RaceGenerateTask(OatFileAssistantTest & test,const std::string & dex_location,const std::string & oat_location,Mutex * lock)1106   RaceGenerateTask(OatFileAssistantTest& test,
1107                    const std::string& dex_location,
1108                    const std::string& oat_location,
1109                    Mutex* lock)
1110       : test_(test),
1111         dex_location_(dex_location),
1112         oat_location_(oat_location),
1113         lock_(lock),
1114         loaded_oat_file_(nullptr)
1115   {}
1116 
Run(Thread * self ATTRIBUTE_UNUSED)1117   void Run(Thread* self ATTRIBUTE_UNUSED) override {
1118     // Load the dex files, and save a pointer to the loaded oat file, so that
1119     // we can verify only one oat file was loaded for the dex location.
1120     std::vector<std::unique_ptr<const DexFile>> dex_files;
1121     std::vector<std::string> error_msgs;
1122     const OatFile* oat_file = nullptr;
1123     {
1124       MutexLock mu(Thread::Current(), *lock_);
1125       // Create the oat file.
1126       std::vector<std::string> args;
1127       args.push_back("--dex-file=" + dex_location_);
1128       args.push_back("--oat-file=" + oat_location_);
1129       std::string error_msg;
1130       ASSERT_TRUE(test_.Dex2Oat(args, &error_msg)) << error_msg;
1131     }
1132 
1133     dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1134         dex_location_.c_str(),
1135         Runtime::Current()->GetSystemClassLoader(),
1136         /*dex_elements=*/nullptr,
1137         &oat_file,
1138         &error_msgs);
1139     CHECK(!dex_files.empty()) << android::base::Join(error_msgs, '\n');
1140     if (dex_files[0]->GetOatDexFile() != nullptr) {
1141       loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile();
1142     }
1143     CHECK_EQ(loaded_oat_file_, oat_file);
1144   }
1145 
GetLoadedOatFile() const1146   const OatFile* GetLoadedOatFile() const {
1147     return loaded_oat_file_;
1148   }
1149 
1150  private:
1151   OatFileAssistantTest& test_;
1152   std::string dex_location_;
1153   std::string oat_location_;
1154   Mutex* lock_;
1155   const OatFile* loaded_oat_file_;
1156 };
1157 
1158 // Test the case where dex2oat invocations race with multiple processes trying to
1159 // load the oat file.
TEST_F(OatFileAssistantTest,RaceToGenerate)1160 TEST_F(OatFileAssistantTest, RaceToGenerate) {
1161   std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
1162   std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat";
1163 
1164   // Start the runtime to initialize the system's class loader.
1165   Thread::Current()->TransitionFromSuspendedToRunnable();
1166   runtime_->Start();
1167 
1168   // We use the lib core dex file, because it's large, and hopefully should
1169   // take a while to generate.
1170   Copy(GetLibCoreDexFileNames()[0], dex_location);
1171 
1172   const size_t kNumThreads = 32;
1173   Thread* self = Thread::Current();
1174   ThreadPool thread_pool("Oat file assistant test thread pool", kNumThreads);
1175   std::vector<std::unique_ptr<RaceGenerateTask>> tasks;
1176   Mutex lock("RaceToGenerate");
1177   for (size_t i = 0; i < kNumThreads; i++) {
1178     std::unique_ptr<RaceGenerateTask> task(
1179         new RaceGenerateTask(*this, dex_location, oat_location, &lock));
1180     thread_pool.AddTask(self, task.get());
1181     tasks.push_back(std::move(task));
1182   }
1183   thread_pool.StartWorkers(self);
1184   thread_pool.Wait(self, /* do_work= */ true, /* may_hold_locks= */ false);
1185 
1186   // Verify that tasks which got an oat file got a unique one.
1187   std::set<const OatFile*> oat_files;
1188   for (auto& task : tasks) {
1189     const OatFile* oat_file = task->GetLoadedOatFile();
1190     if (oat_file != nullptr) {
1191       EXPECT_TRUE(oat_files.find(oat_file) == oat_files.end());
1192       oat_files.insert(oat_file);
1193     }
1194   }
1195 }
1196 
1197 // Case: We have a DEX file and an ODEX file, and no OAT file,
1198 // Expect: We should load the odex file executable.
TEST_F(DexoptTest,LoadDexOdexNoOat)1199 TEST_F(DexoptTest, LoadDexOdexNoOat) {
1200   std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
1201   std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
1202 
1203   // Create the dex and odex files
1204   Copy(GetDexSrc1(), dex_location);
1205   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1206 
1207   // Load the oat using an executable oat file assistant.
1208   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1209 
1210   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1211   ASSERT_TRUE(oat_file.get() != nullptr);
1212   EXPECT_TRUE(oat_file->IsExecutable());
1213   std::vector<std::unique_ptr<const DexFile>> dex_files;
1214   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1215   EXPECT_EQ(1u, dex_files.size());
1216 }
1217 
1218 // Case: We have a MultiDEX file and an ODEX file, and no OAT file.
1219 // Expect: We should load the odex file executable.
TEST_F(DexoptTest,LoadMultiDexOdexNoOat)1220 TEST_F(DexoptTest, LoadMultiDexOdexNoOat) {
1221   std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
1222   std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
1223 
1224   // Create the dex and odex files
1225   Copy(GetMultiDexSrc1(), dex_location);
1226   GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
1227 
1228   // Load the oat using an executable oat file assistant.
1229   OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
1230 
1231   std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
1232   ASSERT_TRUE(oat_file.get() != nullptr);
1233   EXPECT_TRUE(oat_file->IsExecutable());
1234   std::vector<std::unique_ptr<const DexFile>> dex_files;
1235   dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
1236   EXPECT_EQ(2u, dex_files.size());
1237 }
1238 
TEST(OatFileAssistantUtilsTest,DexLocationToOdexFilename)1239 TEST(OatFileAssistantUtilsTest, DexLocationToOdexFilename) {
1240   std::string error_msg;
1241   std::string odex_file;
1242 
1243   EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1244         "/foo/bar/baz.jar", InstructionSet::kArm, &odex_file, &error_msg)) << error_msg;
1245   EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1246 
1247   EXPECT_TRUE(OatFileAssistant::DexLocationToOdexFilename(
1248         "/foo/bar/baz.funnyext", InstructionSet::kArm, &odex_file, &error_msg)) << error_msg;
1249   EXPECT_EQ("/foo/bar/oat/arm/baz.odex", odex_file);
1250 
1251   EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename(
1252         "nopath.jar", InstructionSet::kArm, &odex_file, &error_msg));
1253   EXPECT_FALSE(OatFileAssistant::DexLocationToOdexFilename(
1254         "/foo/bar/baz_noext", InstructionSet::kArm, &odex_file, &error_msg));
1255 }
1256 
1257 // Verify the dexopt status values from dalvik.system.DexFile
1258 // match the OatFileAssistant::DexOptStatus values.
TEST_F(OatFileAssistantTest,DexOptStatusValues)1259 TEST_F(OatFileAssistantTest, DexOptStatusValues) {
1260   std::pair<OatFileAssistant::DexOptNeeded, const char*> mapping[] = {
1261     {OatFileAssistant::kNoDexOptNeeded, "NO_DEXOPT_NEEDED"},
1262     {OatFileAssistant::kDex2OatFromScratch, "DEX2OAT_FROM_SCRATCH"},
1263     {OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"},
1264     {OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"},
1265   };
1266 
1267   ScopedObjectAccess soa(Thread::Current());
1268   StackHandleScope<1> hs(soa.Self());
1269   ClassLinker* linker = Runtime::Current()->GetClassLinker();
1270   Handle<mirror::Class> dexfile(
1271       hs.NewHandle(linker->FindSystemClass(soa.Self(), "Ldalvik/system/DexFile;")));
1272   ASSERT_FALSE(dexfile == nullptr);
1273   linker->EnsureInitialized(soa.Self(), dexfile, true, true);
1274 
1275   for (std::pair<OatFileAssistant::DexOptNeeded, const char*> field : mapping) {
1276     ArtField* art_field = mirror::Class::FindStaticField(
1277         soa.Self(), dexfile.Get(), field.second, "I");
1278     ASSERT_FALSE(art_field == nullptr);
1279     EXPECT_EQ(art_field->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
1280     EXPECT_EQ(field.first, art_field->GetInt(dexfile.Get()));
1281   }
1282 }
1283 
TEST_F(OatFileAssistantTest,GetDexOptNeededWithOutOfDateContext)1284 TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) {
1285   std::string dex_location = GetScratchDir() + "/TestDex.jar";
1286   std::string odex_location = GetOdexDir() + "/TestDex.odex";
1287 
1288   std::string context_location = GetScratchDir() + "/ContextDex.jar";
1289   Copy(GetDexSrc1(), dex_location);
1290   Copy(GetDexSrc2(), context_location);
1291 
1292   std::string context_str = "PCL[" + context_location + "]";
1293 
1294   std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
1295   ASSERT_TRUE(context != nullptr);
1296   ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, ""));
1297 
1298   std::string error_msg;
1299   std::vector<std::string> args;
1300   args.push_back("--dex-file=" + dex_location);
1301   args.push_back("--oat-file=" + odex_location);
1302   args.push_back("--class-loader-context=" + context_str);
1303   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
1304 
1305   // Update the context by overriding the jar file.
1306   Copy(GetMultiDexSrc2(), context_location);
1307 
1308   {
1309     std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
1310     ASSERT_TRUE(updated_context != nullptr);
1311     OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1312     // DexOptNeeded should advise compilation from scratch when the context changes.
1313     EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
1314               GetDexOptNeeded(&oat_file_assistant,
1315                     CompilerFilter::kDefaultCompilerFilter,
1316                     updated_context));
1317   }
1318   {
1319     std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
1320     ASSERT_TRUE(updated_context != nullptr);
1321     OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
1322     // Now check that DexOptNeeded does not advise compilation if we only extracted the file.
1323     args.push_back("--compiler-filter=extract");
1324     ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
1325     EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
1326               GetDexOptNeeded(&oat_file_assistant,
1327                     CompilerFilter::kExtract,
1328                     updated_context));
1329   }
1330 }
1331 
1332 // Test that GetLocation of a dex file is the same whether the dex
1333 // filed is backed by an oat file or not.
TEST_F(OatFileAssistantTest,GetDexLocation)1334 TEST_F(OatFileAssistantTest, GetDexLocation) {
1335   std::string dex_location = GetScratchDir() + "/TestDex.jar";
1336   std::string oat_location = GetOdexDir() + "/TestDex.odex";
1337   std::string art_location = GetOdexDir() + "/TestDex.art";
1338 
1339   // Start the runtime to initialize the system's class loader.
1340   Thread::Current()->TransitionFromSuspendedToRunnable();
1341   runtime_->Start();
1342 
1343   Copy(GetDexSrc1(), dex_location);
1344 
1345   std::vector<std::unique_ptr<const DexFile>> dex_files;
1346   std::vector<std::string> error_msgs;
1347   const OatFile* oat_file = nullptr;
1348 
1349   dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1350       dex_location.c_str(),
1351       Runtime::Current()->GetSystemClassLoader(),
1352       /*dex_elements=*/nullptr,
1353       &oat_file,
1354       &error_msgs);
1355   ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
1356   EXPECT_EQ(oat_file, nullptr);
1357   std::string stored_dex_location = dex_files[0]->GetLocation();
1358   {
1359     // Create the oat file.
1360     std::vector<std::string> args;
1361     args.push_back("--dex-file=" + dex_location);
1362     args.push_back("--dex-location=TestDex.jar");
1363     args.push_back("--oat-file=" + oat_location);
1364     args.push_back("--app-image-file=" + art_location);
1365     std::string error_msg;
1366     ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
1367   }
1368   dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1369       dex_location.c_str(),
1370       Runtime::Current()->GetSystemClassLoader(),
1371       /*dex_elements=*/nullptr,
1372       &oat_file,
1373       &error_msgs);
1374   ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
1375   ASSERT_NE(oat_file, nullptr);
1376   std::string oat_stored_dex_location = dex_files[0]->GetLocation();
1377   EXPECT_EQ(oat_stored_dex_location, stored_dex_location);
1378 }
1379 
1380 // Test that a dex file on the platform location gets the right hiddenapi domain,
1381 // regardless of whether it has a backing oat file.
TEST_F(OatFileAssistantTest,SystemFrameworkDir)1382 TEST_F(OatFileAssistantTest, SystemFrameworkDir) {
1383   std::string filebase = "OatFileAssistantTestSystemFrameworkDir";
1384   std::string dex_location = GetAndroidRoot() + "/framework/" + filebase + ".jar";
1385   Copy(GetDexSrc1(), dex_location);
1386 
1387   std::string odex_dir = GetAndroidRoot() + "/framework/oat/";
1388   mkdir(odex_dir.c_str(), 0700);
1389   odex_dir = odex_dir + std::string(GetInstructionSetString(kRuntimeISA));
1390   mkdir(odex_dir.c_str(), 0700);
1391   std::string oat_location = odex_dir + "/" + filebase + ".odex";
1392   std::string art_location = odex_dir + "/" + filebase + ".art";
1393   // Clean up in case previous run crashed.
1394   remove(oat_location.c_str());
1395 
1396   // Start the runtime to initialize the system's class loader.
1397   Thread::Current()->TransitionFromSuspendedToRunnable();
1398   runtime_->Start();
1399 
1400   std::vector<std::unique_ptr<const DexFile>> dex_files_first;
1401   std::vector<std::unique_ptr<const DexFile>> dex_files_second;
1402   std::vector<std::string> error_msgs;
1403   const OatFile* oat_file = nullptr;
1404 
1405   dex_files_first = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1406       dex_location.c_str(),
1407       Runtime::Current()->GetSystemClassLoader(),
1408       /*dex_elements=*/nullptr,
1409       &oat_file,
1410       &error_msgs);
1411   ASSERT_EQ(dex_files_first.size(), 1u) << android::base::Join(error_msgs, "\n");
1412   EXPECT_EQ(oat_file, nullptr) << dex_location;
1413   EXPECT_EQ(dex_files_first[0]->GetOatDexFile(), nullptr);
1414 
1415   // Register the dex file to get a domain.
1416   {
1417     ScopedObjectAccess soa(Thread::Current());
1418     Runtime::Current()->GetClassLinker()->RegisterDexFile(
1419         *dex_files_first[0],
1420         soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader()));
1421   }
1422   std::string stored_dex_location = dex_files_first[0]->GetLocation();
1423   EXPECT_EQ(dex_files_first[0]->GetHiddenapiDomain(), hiddenapi::Domain::kPlatform);
1424   {
1425     // Create the oat file.
1426     std::vector<std::string> args;
1427     args.push_back("--dex-file=" + dex_location);
1428     args.push_back("--dex-location=" + filebase + ".jar");
1429     args.push_back("--oat-file=" + oat_location);
1430     args.push_back("--app-image-file=" + art_location);
1431     std::string error_msg;
1432     ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
1433   }
1434   dex_files_second = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1435       dex_location.c_str(),
1436       Runtime::Current()->GetSystemClassLoader(),
1437       /*dex_elements=*/nullptr,
1438       &oat_file,
1439       &error_msgs);
1440   ASSERT_EQ(dex_files_second.size(), 1u) << android::base::Join(error_msgs, "\n");
1441   ASSERT_NE(oat_file, nullptr);
1442   EXPECT_NE(dex_files_second[0]->GetOatDexFile(), nullptr);
1443   EXPECT_NE(dex_files_second[0]->GetOatDexFile()->GetOatFile(), nullptr);
1444 
1445   // Register the dex file to get a domain.
1446   {
1447     ScopedObjectAccess soa(Thread::Current());
1448     Runtime::Current()->GetClassLinker()->RegisterDexFile(
1449         *dex_files_second[0],
1450         soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader()));
1451   }
1452   std::string oat_stored_dex_location = dex_files_second[0]->GetLocation();
1453   EXPECT_EQ(oat_stored_dex_location, stored_dex_location);
1454   EXPECT_EQ(dex_files_second[0]->GetHiddenapiDomain(), hiddenapi::Domain::kPlatform);
1455   EXPECT_EQ(0, remove(oat_location.c_str()));
1456 }
1457 
1458 // Make sure OAT files that require app images are not loaded as executable.
TEST_F(OatFileAssistantTest,LoadOatNoArt)1459 TEST_F(OatFileAssistantTest, LoadOatNoArt) {
1460   std::string dex_location = GetScratchDir() + "/TestDex.jar";
1461   std::string odex_location = GetOdexDir() + "/TestDex.odex";
1462   std::string art_location = GetOdexDir() + "/TestDex.art";
1463   Copy(GetDexSrc1(), dex_location);
1464   GenerateOdexForTest(dex_location,
1465                       odex_location,
1466                       CompilerFilter::kSpeed,
1467                       "install",
1468                       {
1469                           "--app-image-file=" + art_location,
1470                       });
1471 
1472   unlink(art_location.c_str());
1473 
1474   std::vector<std::string> error_msgs;
1475   const OatFile* oat_file = nullptr;
1476 
1477   // Start the runtime to initialize the system's class loader.
1478   Thread::Current()->TransitionFromSuspendedToRunnable();
1479   runtime_->Start();
1480 
1481   const auto dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
1482       dex_location.c_str(),
1483       Runtime::Current()->GetSystemClassLoader(),
1484       /*dex_elements=*/nullptr,
1485       &oat_file,
1486       &error_msgs);
1487 
1488   EXPECT_FALSE(dex_files.empty());
1489   ASSERT_NE(oat_file, nullptr);
1490   EXPECT_FALSE(oat_file->IsExecutable());
1491 }
1492 
1493 // TODO: More Tests:
1494 //  * Test class linker falls back to unquickened dex for DexNoOat
1495 //  * Test class linker falls back to unquickened dex for MultiDexNoOat
1496 //  * Test using secondary isa
1497 //  * Test for status of oat while oat is being generated (how?)
1498 //  * Test case where 32 and 64 bit boot class paths differ,
1499 //      and we ask IsInBootClassPath for a class in exactly one of the 32 or
1500 //      64 bit boot class paths.
1501 //  * Test unexpected scenarios (?):
1502 //    - Dex is stripped, don't have odex.
1503 //    - Oat file corrupted after status check, before reload unexecutable
1504 //    because it's unrelocated and no dex2oat
1505 }  // namespace art
1506