blob: 73b065feaa84b312a51cd379e4ce8066d67742b9 [file] [log] [blame]
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -07001/*
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 "dex_file.h"
26#include "gc/space/image_space.h"
27#include "oat_file_assistant.h"
28#include "thread-inl.h"
29
30namespace art {
31
32// For b/21333911.
33static constexpr bool kDuplicateClassesCheck = false;
34
35const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) {
Nicolas Geoffray72da5e72015-10-13 07:26:45 +000036 ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -070037 DCHECK(oat_file != nullptr);
38 if (kIsDebugBuild) {
39 for (const std::unique_ptr<const OatFile>& existing : oat_files_) {
40 CHECK_NE(oat_file.get(), existing.get()) << oat_file->GetLocation();
41 // Check that we don't have an oat file with the same address. Copies of the same oat file
42 // should be loaded at different addresses.
43 CHECK_NE(oat_file->Begin(), existing->Begin()) << "Oat file already mapped at that location";
44 }
45 }
46 have_non_pic_oat_file_ = have_non_pic_oat_file_ || !oat_file->IsPic();
Nicolas Geoffray72da5e72015-10-13 07:26:45 +000047 oat_files_.push_back(std::move(oat_file));
48 return oat_files_.back().get();
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -070049}
50
51const OatFile* OatFileManager::FindOpenedOatFileFromOatLocation(const std::string& oat_location)
52 const {
53 ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
54 for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
55 if (oat_file->GetLocation() == oat_location) {
56 return oat_file.get();
57 }
58 }
59 return nullptr;
60}
61
62const OatFile* OatFileManager::GetBootOatFile() const {
63 gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
64 if (image_space == nullptr) {
65 return nullptr;
66 }
67 return image_space->GetOatFile();
68}
69
70const OatFile* OatFileManager::GetPrimaryOatFile() const {
71 ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
72 const OatFile* boot_oat_file = GetBootOatFile();
73 if (boot_oat_file != nullptr) {
74 for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) {
75 if (oat_file.get() != boot_oat_file) {
76 return oat_file.get();
77 }
78 }
79 }
80 return nullptr;
81}
82
83OatFileManager::~OatFileManager() {
84}
85
86const OatFile* OatFileManager::RegisterImageOatFile(gc::space::ImageSpace* space) {
87 return RegisterOatFile(space->ReleaseOatFile());
88}
89
90class DexFileAndClassPair : ValueObject {
91 public:
92 DexFileAndClassPair(const DexFile* dex_file, size_t current_class_index, bool from_loaded_oat)
93 : cached_descriptor_(GetClassDescriptor(dex_file, current_class_index)),
94 dex_file_(dex_file),
95 current_class_index_(current_class_index),
96 from_loaded_oat_(from_loaded_oat) {}
97
Nicolas Geoffray72da5e72015-10-13 07:26:45 +000098 DexFileAndClassPair(DexFileAndClassPair&& rhs) {
99 *this = std::move(rhs);
100 }
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -0700101
Nicolas Geoffray72da5e72015-10-13 07:26:45 +0000102 DexFileAndClassPair& operator=(DexFileAndClassPair&& rhs) {
103 cached_descriptor_ = rhs.cached_descriptor_;
104 dex_file_ = std::move(rhs.dex_file_);
105 current_class_index_ = rhs.current_class_index_;
106 from_loaded_oat_ = rhs.from_loaded_oat_;
107 return *this;
108 }
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -0700109
110 const char* GetCachedDescriptor() const {
111 return cached_descriptor_;
112 }
113
114 bool operator<(const DexFileAndClassPair& rhs) const {
115 const int cmp = strcmp(cached_descriptor_, rhs.cached_descriptor_);
116 if (cmp != 0) {
117 // Note that the order must be reversed. We want to iterate over the classes in dex files.
118 // They are sorted lexicographically. Thus, the priority-queue must be a min-queue.
119 return cmp > 0;
120 }
121 return dex_file_ < rhs.dex_file_;
122 }
123
124 bool DexFileHasMoreClasses() const {
125 return current_class_index_ + 1 < dex_file_->NumClassDefs();
126 }
127
128 void Next() {
129 ++current_class_index_;
130 }
131
132 size_t GetCurrentClassIndex() const {
133 return current_class_index_;
134 }
135
136 bool FromLoadedOat() const {
137 return from_loaded_oat_;
138 }
139
140 const DexFile* GetDexFile() const {
141 return dex_file_.get();
142 }
143
144 private:
145 static const char* GetClassDescriptor(const DexFile* dex_file, size_t index) {
146 DCHECK(IsUint<16>(index));
147 const DexFile::ClassDef& class_def = dex_file->GetClassDef(static_cast<uint16_t>(index));
148 return dex_file->StringByTypeIdx(class_def.class_idx_);
149 }
150
151 const char* cached_descriptor_;
152 std::unique_ptr<const DexFile> dex_file_;
153 size_t current_class_index_;
154 bool from_loaded_oat_; // We only need to compare mismatches between what we load now
155 // and what was loaded before. Any old duplicates must have been
156 // OK, and any new "internal" duplicates are as well (they must
157 // be from multidex, which resolves correctly).
158};
159
160static void AddDexFilesFromOat(const OatFile* oat_file,
161 bool already_loaded,
162 /*out*/std::priority_queue<DexFileAndClassPair>* heap) {
163 for (const OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
164 std::string error;
165 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error);
166 if (dex_file == nullptr) {
167 LOG(WARNING) << "Could not create dex file from oat file: " << error;
168 } else if (dex_file->NumClassDefs() > 0U) {
169 heap->emplace(dex_file.release(), /*current_class_index*/0U, already_loaded);
170 }
171 }
172}
173
174static void AddNext(/*inout*/DexFileAndClassPair* original,
175 /*inout*/std::priority_queue<DexFileAndClassPair>* heap) {
176 if (original->DexFileHasMoreClasses()) {
177 original->Next();
178 heap->push(std::move(*original));
179 }
180}
181
182// Check for class-def collisions in dex files.
183//
184// This works by maintaining a heap with one class from each dex file, sorted by the class
185// descriptor. Then a dex-file/class pair is continually removed from the heap and compared
186// against the following top element. If the descriptor is the same, it is now checked whether
187// the two elements agree on whether their dex file was from an already-loaded oat-file or the
188// new oat file. Any disagreement indicates a collision.
189bool OatFileManager::HasCollisions(const OatFile* oat_file,
190 std::string* error_msg /*out*/) const {
191 DCHECK(oat_file != nullptr);
192 DCHECK(error_msg != nullptr);
193 if (!kDuplicateClassesCheck) {
194 return false;
195 }
196
197 // Dex files are registered late - once a class is actually being loaded. We have to compare
198 // against the open oat files. Take the oat_file_manager_lock_ that protects oat_files_ accesses.
199 ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
200
201 std::priority_queue<DexFileAndClassPair> queue;
202
203 // Add dex files from already loaded oat files, but skip boot.
204 const OatFile* boot_oat = GetBootOatFile();
205 for (const std::unique_ptr<const OatFile>& loaded_oat_file : oat_files_) {
206 if (loaded_oat_file.get() != boot_oat) {
207 AddDexFilesFromOat(loaded_oat_file.get(), /*already_loaded*/true, &queue);
208 }
209 }
210
211 if (queue.empty()) {
212 // No other oat files, return early.
213 return false;
214 }
215
216 // Add dex files from the oat file to check.
217 AddDexFilesFromOat(oat_file, /*already_loaded*/false, &queue);
218
219 // Now drain the queue.
220 while (!queue.empty()) {
221 // Modifying the top element is only safe if we pop right after.
222 DexFileAndClassPair compare_pop(std::move(const_cast<DexFileAndClassPair&>(queue.top())));
223 queue.pop();
224
225 // Compare against the following elements.
226 while (!queue.empty()) {
227 DexFileAndClassPair top(std::move(const_cast<DexFileAndClassPair&>(queue.top())));
228
229 if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
230 // Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
231 if (compare_pop.FromLoadedOat() != top.FromLoadedOat()) {
232 *error_msg =
233 StringPrintf("Found duplicated class when checking oat files: '%s' in %s and %s",
234 compare_pop.GetCachedDescriptor(),
235 compare_pop.GetDexFile()->GetLocation().c_str(),
236 top.GetDexFile()->GetLocation().c_str());
237 return true;
238 }
239 // Pop it.
240 queue.pop();
241 AddNext(&top, &queue);
242 } else {
243 // Something else. Done here.
244 break;
245 }
246 }
247 AddNext(&compare_pop, &queue);
248 }
249
250 return false;
251}
252
253std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
254 const char* dex_location,
255 const char* oat_location,
256 std::vector<std::string>* error_msgs) {
257 CHECK(dex_location != nullptr);
258 CHECK(error_msgs != nullptr);
259
260 // Verify we aren't holding the mutator lock, which could starve GC if we
261 // have to generate or relocate an oat file.
262 Locks::mutator_lock_->AssertNotHeld(Thread::Current());
263
264 OatFileAssistant oat_file_assistant(dex_location,
265 oat_location,
266 kRuntimeISA,
267 !Runtime::Current()->IsAotCompiler());
268
269 // Lock the target oat location to avoid races generating and loading the
270 // oat file.
271 std::string error_msg;
272 if (!oat_file_assistant.Lock(/*out*/&error_msg)) {
273 // Don't worry too much if this fails. If it does fail, it's unlikely we
274 // can generate an oat file anyway.
275 VLOG(class_linker) << "OatFileAssistant::Lock: " << error_msg;
276 }
277
278 const OatFile* source_oat_file = nullptr;
279
280 // Update the oat file on disk if we can. This may fail, but that's okay.
281 // Best effort is all that matters here.
282 if (!oat_file_assistant.MakeUpToDate(/*out*/&error_msg)) {
283 LOG(WARNING) << error_msg;
284 }
285
286 // Get the oat file on disk.
287 std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
288 if (oat_file != nullptr) {
289 // Take the file only if it has no collisions, or we must take it because of preopting.
290 bool accept_oat_file = !HasCollisions(oat_file.get(), /*out*/ &error_msg);
291 if (!accept_oat_file) {
292 // Failed the collision check. Print warning.
293 if (Runtime::Current()->IsDexFileFallbackEnabled()) {
294 LOG(WARNING) << "Found duplicate classes, falling back to interpreter mode for "
295 << dex_location;
296 } else {
297 LOG(WARNING) << "Found duplicate classes, dex-file-fallback disabled, will be failing to "
298 " load classes for " << dex_location;
299 }
300 LOG(WARNING) << error_msg;
301
302 // However, if the app was part of /system and preopted, there is no original dex file
303 // available. In that case grudgingly accept the oat file.
304 if (!DexFile::MaybeDex(dex_location)) {
305 accept_oat_file = true;
306 LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. "
307 << "Allow oat file use. This is potentially dangerous.";
308 }
309 }
310
311 if (accept_oat_file) {
312 VLOG(class_linker) << "Registering " << oat_file->GetLocation();
313 source_oat_file = RegisterOatFile(std::move(oat_file));
Mathieu Chartierf9c6fc62015-10-07 11:44:05 -0700314 }
315 }
316
317 std::vector<std::unique_ptr<const DexFile>> dex_files;
318
319 // Load the dex files from the oat file.
320 if (source_oat_file != nullptr) {
321 dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location);
322 if (dex_files.empty()) {
323 error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation());
324 }
325 }
326
327 // Fall back to running out of the original dex file if we couldn't load any
328 // dex_files from the oat file.
329 if (dex_files.empty()) {
330 if (oat_file_assistant.HasOriginalDexFiles()) {
331 if (Runtime::Current()->IsDexFileFallbackEnabled()) {
332 if (!DexFile::Open(dex_location, dex_location, /*out*/ &error_msg, &dex_files)) {
333 LOG(WARNING) << error_msg;
334 error_msgs->push_back("Failed to open dex files from " + std::string(dex_location));
335 }
336 } else {
337 error_msgs->push_back("Fallback mode disabled, skipping dex files.");
338 }
339 } else {
340 error_msgs->push_back("No original dex files found for dex location "
341 + std::string(dex_location));
342 }
343 }
344 return dex_files;
345}
346
347} // namespace art