oat_file_manager.cc revision 6cc91e4d8c5956d3c4323b416f2a344bf848f741
1/*
2 * Copyright (C) 2015 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_manager.h"
18
19#include <memory>
20#include <queue>
21#include <vector>
22
23#include "base/logging.h"
24#include "base/stl_util.h"
25#include "class_linker.h"
26#include "dex_file-inl.h"
27#include "gc/scoped_gc_critical_section.h"
28#include "gc/space/image_space.h"
29#include "handle_scope-inl.h"
30#include "mirror/class_loader.h"
31#include "oat_file_assistant.h"
32#include "scoped_thread_state_change.h"
33#include "thread-inl.h"
34#include "thread_list.h"
35
36namespace art {
37
38// For b/21333911.
39// Only enabled for debug builds to prevent bit rot. There are too many performance regressions for
40// normal builds.
41static constexpr bool kDuplicateClassesCheck = kIsDebugBuild;
42
43// If true, then we attempt to load the application image if it exists.
44static constexpr bool kEnableAppImage = true;
45
46const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) {
47  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
48  DCHECK(oat_file != nullptr);
49  if (kIsDebugBuild) {
50    CHECK(oat_files_.find(oat_file) == oat_files_.end());
51    for (const std::unique_ptr<const OatFile>& existing : oat_files_) {
52      CHECK_NE(oat_file.get(), existing.get()) << oat_file->GetLocation();
53      // Check that we don't have an oat file with the same address. Copies of the same oat file
54      // should be loaded at different addresses.
55      CHECK_NE(oat_file->Begin(), existing->Begin()) << "Oat file already mapped at that location";
56    }
57  }
58  have_non_pic_oat_file_ = have_non_pic_oat_file_ || !oat_file->IsPic();
59  const OatFile* ret = oat_file.get();
60  oat_files_.insert(std::move(oat_file));
61  return ret;
62}
63
64void OatFileManager::UnRegisterAndDeleteOatFile(const OatFile* oat_file) {
65  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
66  DCHECK(oat_file != nullptr);
67  std::unique_ptr<const OatFile> compare(oat_file);
68  auto it = oat_files_.find(compare);
69  CHECK(it != oat_files_.end());
70  oat_files_.erase(it);
71  compare.release();
72}
73
74const OatFile* OatFileManager::FindOpenedOatFileFromOatLocation(const std::string& oat_location)
75    const {
76  ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
77  return FindOpenedOatFileFromOatLocationLocked(oat_location);
78}
79
80const OatFile* OatFileManager::FindOpenedOatFileFromOatLocationLocked(
81    const std::string& oat_location) const {
82  for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
83    if (oat_file->GetLocation() == oat_location) {
84      return oat_file.get();
85    }
86  }
87  return nullptr;
88}
89
90std::vector<const OatFile*> OatFileManager::GetBootOatFiles() const {
91  std::vector<const OatFile*> oat_files;
92  std::vector<gc::space::ImageSpace*> image_spaces =
93      Runtime::Current()->GetHeap()->GetBootImageSpaces();
94  for (gc::space::ImageSpace* image_space : image_spaces) {
95    oat_files.push_back(image_space->GetOatFile());
96  }
97  return oat_files;
98}
99
100const OatFile* OatFileManager::GetPrimaryOatFile() const {
101  ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
102  std::vector<const OatFile*> boot_oat_files = GetBootOatFiles();
103  if (!boot_oat_files.empty()) {
104    for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
105      if (std::find(boot_oat_files.begin(), boot_oat_files.end(), oat_file.get()) ==
106          boot_oat_files.end()) {
107        return oat_file.get();
108      }
109    }
110  }
111  return nullptr;
112}
113
114OatFileManager::~OatFileManager() {
115  // Explicitly clear oat_files_ since the OatFile destructor calls back into OatFileManager for
116  // UnRegisterOatFileLocation.
117  oat_files_.clear();
118}
119
120std::vector<const OatFile*> OatFileManager::RegisterImageOatFiles(
121    std::vector<gc::space::ImageSpace*> spaces) {
122  std::vector<const OatFile*> oat_files;
123  for (gc::space::ImageSpace* space : spaces) {
124    oat_files.push_back(RegisterOatFile(space->ReleaseOatFile()));
125  }
126  return oat_files;
127}
128
129class DexFileAndClassPair : ValueObject {
130 public:
131  DexFileAndClassPair(const DexFile* dex_file, size_t current_class_index, bool from_loaded_oat)
132     : cached_descriptor_(GetClassDescriptor(dex_file, current_class_index)),
133       dex_file_(dex_file),
134       current_class_index_(current_class_index),
135       from_loaded_oat_(from_loaded_oat) {}
136
137  DexFileAndClassPair(const DexFileAndClassPair& rhs) = default;
138
139  DexFileAndClassPair& operator=(const DexFileAndClassPair& rhs) = default;
140
141  const char* GetCachedDescriptor() const {
142    return cached_descriptor_;
143  }
144
145  bool operator<(const DexFileAndClassPair& rhs) const {
146    const int cmp = strcmp(cached_descriptor_, rhs.cached_descriptor_);
147    if (cmp != 0) {
148      // Note that the order must be reversed. We want to iterate over the classes in dex files.
149      // They are sorted lexicographically. Thus, the priority-queue must be a min-queue.
150      return cmp > 0;
151    }
152    return dex_file_ < rhs.dex_file_;
153  }
154
155  bool DexFileHasMoreClasses() const {
156    return current_class_index_ + 1 < dex_file_->NumClassDefs();
157  }
158
159  void Next() {
160    ++current_class_index_;
161    cached_descriptor_ = GetClassDescriptor(dex_file_.get(), current_class_index_);
162  }
163
164  size_t GetCurrentClassIndex() const {
165    return current_class_index_;
166  }
167
168  bool FromLoadedOat() const {
169    return from_loaded_oat_;
170  }
171
172  const DexFile* GetDexFile() const {
173    return dex_file_.get();
174  }
175
176 private:
177  static const char* GetClassDescriptor(const DexFile* dex_file, size_t index) {
178    DCHECK(IsUint<16>(index));
179    const DexFile::ClassDef& class_def = dex_file->GetClassDef(static_cast<uint16_t>(index));
180    return dex_file->StringByTypeIdx(class_def.class_idx_);
181  }
182
183  const char* cached_descriptor_;
184  std::shared_ptr<const DexFile> dex_file_;
185  size_t current_class_index_;
186  bool from_loaded_oat_;  // We only need to compare mismatches between what we load now
187                          // and what was loaded before. Any old duplicates must have been
188                          // OK, and any new "internal" duplicates are as well (they must
189                          // be from multidex, which resolves correctly).
190};
191
192static void AddDexFilesFromOat(const OatFile* oat_file,
193                               bool already_loaded,
194                               /*out*/std::priority_queue<DexFileAndClassPair>* heap) {
195  for (const OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
196    std::string error;
197    std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error);
198    if (dex_file == nullptr) {
199      LOG(WARNING) << "Could not create dex file from oat file: " << error;
200    } else if (dex_file->NumClassDefs() > 0U) {
201      heap->emplace(dex_file.release(), /*current_class_index*/0U, already_loaded);
202    }
203  }
204}
205
206static void AddNext(/*inout*/DexFileAndClassPair* original,
207                    /*inout*/std::priority_queue<DexFileAndClassPair>* heap) {
208  if (original->DexFileHasMoreClasses()) {
209    original->Next();
210    heap->push(std::move(*original));
211  }
212}
213
214// Check for class-def collisions in dex files.
215//
216// This works by maintaining a heap with one class from each dex file, sorted by the class
217// descriptor. Then a dex-file/class pair is continually removed from the heap and compared
218// against the following top element. If the descriptor is the same, it is now checked whether
219// the two elements agree on whether their dex file was from an already-loaded oat-file or the
220// new oat file. Any disagreement indicates a collision.
221bool OatFileManager::HasCollisions(const OatFile* oat_file,
222                                   std::string* error_msg /*out*/) const {
223  DCHECK(oat_file != nullptr);
224  DCHECK(error_msg != nullptr);
225  if (!kDuplicateClassesCheck) {
226    return false;
227  }
228
229  // Dex files are registered late - once a class is actually being loaded. We have to compare
230  // against the open oat files. Take the oat_file_manager_lock_ that protects oat_files_ accesses.
231  ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
232
233  std::priority_queue<DexFileAndClassPair> queue;
234
235  // Add dex files from already loaded oat files, but skip boot.
236  std::vector<const OatFile*> boot_oat_files = GetBootOatFiles();
237  // The same OatFile can be loaded multiple times at different addresses. In this case, we don't
238  // need to check both against each other since they would have resolved the same way at compile
239  // time.
240  std::unordered_set<std::string> unique_locations;
241  for (const std::unique_ptr<const OatFile>& loaded_oat_file : oat_files_) {
242    DCHECK_NE(loaded_oat_file.get(), oat_file);
243    const std::string& location = loaded_oat_file->GetLocation();
244    if (std::find(boot_oat_files.begin(), boot_oat_files.end(), loaded_oat_file.get()) ==
245        boot_oat_files.end() && location != oat_file->GetLocation() &&
246        unique_locations.find(location) == unique_locations.end()) {
247      unique_locations.insert(location);
248      AddDexFilesFromOat(loaded_oat_file.get(), /*already_loaded*/true, &queue);
249    }
250  }
251
252  if (queue.empty()) {
253    // No other oat files, return early.
254    return false;
255  }
256
257  // Add dex files from the oat file to check.
258  AddDexFilesFromOat(oat_file, /*already_loaded*/false, &queue);
259
260  // Now drain the queue.
261  while (!queue.empty()) {
262    // Modifying the top element is only safe if we pop right after.
263    DexFileAndClassPair compare_pop(queue.top());
264    queue.pop();
265
266    // Compare against the following elements.
267    while (!queue.empty()) {
268      DexFileAndClassPair top(queue.top());
269
270      if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
271        // Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
272        if (compare_pop.FromLoadedOat() != top.FromLoadedOat()) {
273          *error_msg =
274              StringPrintf("Found duplicated class when checking oat files: '%s' in %s and %s",
275                           compare_pop.GetCachedDescriptor(),
276                           compare_pop.GetDexFile()->GetLocation().c_str(),
277                           top.GetDexFile()->GetLocation().c_str());
278          return true;
279        }
280        queue.pop();
281        AddNext(&top, &queue);
282      } else {
283        // Something else. Done here.
284        break;
285      }
286    }
287    AddNext(&compare_pop, &queue);
288  }
289
290  return false;
291}
292
293std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
294    const char* dex_location,
295    const char* oat_location,
296    jobject class_loader,
297    jobjectArray dex_elements,
298    const OatFile** out_oat_file,
299    std::vector<std::string>* error_msgs) {
300  CHECK(dex_location != nullptr);
301  CHECK(error_msgs != nullptr);
302
303  // Verify we aren't holding the mutator lock, which could starve GC if we
304  // have to generate or relocate an oat file.
305  Thread* const self = Thread::Current();
306  Locks::mutator_lock_->AssertNotHeld(self);
307  Runtime* const runtime = Runtime::Current();
308  OatFileAssistant oat_file_assistant(dex_location,
309                                      oat_location,
310                                      kRuntimeISA,
311                                      !runtime->IsAotCompiler());
312
313  // Lock the target oat location to avoid races generating and loading the
314  // oat file.
315  std::string error_msg;
316  if (!oat_file_assistant.Lock(/*out*/&error_msg)) {
317    // Don't worry too much if this fails. If it does fail, it's unlikely we
318    // can generate an oat file anyway.
319    VLOG(class_linker) << "OatFileAssistant::Lock: " << error_msg;
320  }
321
322  const OatFile* source_oat_file = nullptr;
323
324  // Update the oat file on disk if we can. This may fail, but that's okay.
325  // Best effort is all that matters here.
326  if (!oat_file_assistant.MakeUpToDate(/*out*/&error_msg)) {
327    LOG(INFO) << error_msg;
328  }
329
330  // Get the oat file on disk.
331  std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
332
333  if (oat_file != nullptr) {
334    // Take the file only if it has no collisions, or we must take it because of preopting.
335    bool accept_oat_file = !HasCollisions(oat_file.get(), /*out*/ &error_msg);
336    if (!accept_oat_file) {
337      // Failed the collision check. Print warning.
338      if (Runtime::Current()->IsDexFileFallbackEnabled()) {
339        LOG(WARNING) << "Found duplicate classes, falling back to interpreter mode for "
340                     << dex_location;
341      } else {
342        LOG(WARNING) << "Found duplicate classes, dex-file-fallback disabled, will be failing to "
343                        " load classes for " << dex_location;
344      }
345      LOG(WARNING) << error_msg;
346
347      // However, if the app was part of /system and preopted, there is no original dex file
348      // available. In that case grudgingly accept the oat file.
349      if (!DexFile::MaybeDex(dex_location)) {
350        accept_oat_file = true;
351        LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. "
352                     << "Allow oat file use. This is potentially dangerous.";
353      }
354    }
355
356    if (accept_oat_file) {
357      VLOG(class_linker) << "Registering " << oat_file->GetLocation();
358      source_oat_file = RegisterOatFile(std::move(oat_file));
359      *out_oat_file = source_oat_file;
360    }
361  }
362
363  std::vector<std::unique_ptr<const DexFile>> dex_files;
364
365  // Load the dex files from the oat file.
366  if (source_oat_file != nullptr) {
367    bool added_image_space = false;
368    if (source_oat_file->IsExecutable()) {
369      std::unique_ptr<gc::space::ImageSpace> image_space(
370          kEnableAppImage ? oat_file_assistant.OpenImageSpace(source_oat_file) : nullptr);
371      if (image_space != nullptr) {
372        ScopedObjectAccess soa(self);
373        StackHandleScope<1> hs(self);
374        Handle<mirror::ClassLoader> h_loader(
375            hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
376        // Can not load app image without class loader.
377        if (h_loader.Get() != nullptr) {
378          std::string temp_error_msg;
379          // Add image space has a race condition since other threads could be reading from the
380          // spaces array.
381          {
382            ScopedThreadSuspension sts(self, kSuspended);
383            gc::ScopedGCCriticalSection gcs(self,
384                                            gc::kGcCauseAddRemoveAppImageSpace,
385                                            gc::kCollectorTypeAddRemoveAppImageSpace);
386            ScopedSuspendAll ssa("Add image space");
387            runtime->GetHeap()->AddSpace(image_space.get());
388          }
389          added_image_space = true;
390          if (runtime->GetClassLinker()->AddImageSpace(image_space.get(),
391                                                       h_loader,
392                                                       dex_elements,
393                                                       dex_location,
394                                                       /*out*/&dex_files,
395                                                       /*out*/&temp_error_msg)) {
396            // Successfully added image space to heap, release the map so that it does not get
397            // freed.
398            image_space.release();
399          } else {
400            LOG(INFO) << "Failed to add image file " << temp_error_msg;
401            dex_files.clear();
402            {
403              ScopedThreadSuspension sts(self, kSuspended);
404              gc::ScopedGCCriticalSection gcs(self,
405                                              gc::kGcCauseAddRemoveAppImageSpace,
406                                              gc::kCollectorTypeAddRemoveAppImageSpace);
407              ScopedSuspendAll ssa("Remove image space");
408              runtime->GetHeap()->RemoveSpace(image_space.get());
409            }
410            added_image_space = false;
411            // Non-fatal, don't update error_msg.
412          }
413        }
414      }
415    }
416    if (!added_image_space) {
417      DCHECK(dex_files.empty());
418      dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location);
419    }
420    if (dex_files.empty()) {
421      error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation());
422    }
423  }
424
425  // Fall back to running out of the original dex file if we couldn't load any
426  // dex_files from the oat file.
427  if (dex_files.empty()) {
428    if (oat_file_assistant.HasOriginalDexFiles()) {
429      if (Runtime::Current()->IsDexFileFallbackEnabled()) {
430        if (!DexFile::Open(dex_location, dex_location, /*out*/ &error_msg, &dex_files)) {
431          LOG(WARNING) << error_msg;
432          error_msgs->push_back("Failed to open dex files from " + std::string(dex_location));
433        }
434      } else {
435        error_msgs->push_back("Fallback mode disabled, skipping dex files.");
436      }
437    } else {
438      error_msgs->push_back("No original dex files found for dex location "
439          + std::string(dex_location));
440    }
441  }
442  return dex_files;
443}
444
445bool OatFileManager::RegisterOatFileLocation(const std::string& oat_location) {
446  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_count_lock_);
447  auto it = oat_file_count_.find(oat_location);
448  if (it != oat_file_count_.end()) {
449    ++it->second;
450    return false;
451  }
452  oat_file_count_.insert(std::pair<std::string, size_t>(oat_location, 1u));
453  return true;
454}
455
456void OatFileManager::UnRegisterOatFileLocation(const std::string& oat_location) {
457  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_count_lock_);
458  auto it = oat_file_count_.find(oat_location);
459  if (it != oat_file_count_.end()) {
460    --it->second;
461    if (it->second == 0) {
462      oat_file_count_.erase(it);
463    }
464  }
465}
466
467}  // namespace art
468