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