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