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 <fcntl.h>
20 #ifdef __linux__
21 #include <sys/sendfile.h>
22 #else
23 #include <sys/socket.h>
24 #endif
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 #include <set>
30
31 #include "base/logging.h"
32 #include "base/stringprintf.h"
33 #include "compiler_filter.h"
34 #include "class_linker.h"
35 #include "gc/heap.h"
36 #include "gc/space/image_space.h"
37 #include "image.h"
38 #include "oat.h"
39 #include "os.h"
40 #include "runtime.h"
41 #include "scoped_thread_state_change.h"
42 #include "ScopedFd.h"
43 #include "utils.h"
44
45 namespace art {
46
operator <<(std::ostream & stream,const OatFileAssistant::OatStatus status)47 std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status) {
48 switch (status) {
49 case OatFileAssistant::kOatOutOfDate:
50 stream << "kOatOutOfDate";
51 break;
52 case OatFileAssistant::kOatUpToDate:
53 stream << "kOatUpToDate";
54 break;
55 case OatFileAssistant::kOatNeedsRelocation:
56 stream << "kOatNeedsRelocation";
57 break;
58 default:
59 UNREACHABLE();
60 }
61
62 return stream;
63 }
64
OatFileAssistant(const char * dex_location,const InstructionSet isa,bool profile_changed,bool load_executable)65 OatFileAssistant::OatFileAssistant(const char* dex_location,
66 const InstructionSet isa,
67 bool profile_changed,
68 bool load_executable)
69 : OatFileAssistant(dex_location, nullptr, isa, profile_changed, load_executable)
70 { }
71
OatFileAssistant(const char * dex_location,const char * oat_location,const InstructionSet isa,bool profile_changed,bool load_executable)72 OatFileAssistant::OatFileAssistant(const char* dex_location,
73 const char* oat_location,
74 const InstructionSet isa,
75 bool profile_changed,
76 bool load_executable)
77 : isa_(isa), profile_changed_(profile_changed), load_executable_(load_executable) {
78 CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
79 dex_location_.assign(dex_location);
80
81 if (load_executable_ && isa != kRuntimeISA) {
82 LOG(WARNING) << "OatFileAssistant: Load executable specified, "
83 << "but isa is not kRuntimeISA. Will not attempt to load executable.";
84 load_executable_ = false;
85 }
86
87 // If the user gave a target oat location, save that as the cached oat
88 // location now so we won't try to construct the default location later.
89 if (oat_location != nullptr) {
90 cached_oat_file_name_ = std::string(oat_location);
91 cached_oat_file_name_attempted_ = true;
92 cached_oat_file_name_found_ = true;
93 }
94 }
95
~OatFileAssistant()96 OatFileAssistant::~OatFileAssistant() {
97 // Clean up the lock file.
98 if (flock_.HasFile()) {
99 unlink(flock_.GetFile()->GetPath().c_str());
100 }
101 }
102
IsInBootClassPath()103 bool OatFileAssistant::IsInBootClassPath() {
104 // Note: We check the current boot class path, regardless of the ISA
105 // specified by the user. This is okay, because the boot class path should
106 // be the same for all ISAs.
107 // TODO: Can we verify the boot class path is the same for all ISAs?
108 Runtime* runtime = Runtime::Current();
109 ClassLinker* class_linker = runtime->GetClassLinker();
110 const auto& boot_class_path = class_linker->GetBootClassPath();
111 for (size_t i = 0; i < boot_class_path.size(); i++) {
112 if (boot_class_path[i]->GetLocation() == dex_location_) {
113 VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path";
114 return true;
115 }
116 }
117 return false;
118 }
119
Lock(std::string * error_msg)120 bool OatFileAssistant::Lock(std::string* error_msg) {
121 CHECK(error_msg != nullptr);
122 CHECK(!flock_.HasFile()) << "OatFileAssistant::Lock already acquired";
123
124 if (OatFileName() == nullptr) {
125 *error_msg = "Failed to determine lock file";
126 return false;
127 }
128 std::string lock_file_name = *OatFileName() + ".flock";
129
130 if (!flock_.Init(lock_file_name.c_str(), error_msg)) {
131 unlink(lock_file_name.c_str());
132 return false;
133 }
134 return true;
135 }
136
OatFileCompilerFilterIsOkay(CompilerFilter::Filter target)137 bool OatFileAssistant::OatFileCompilerFilterIsOkay(CompilerFilter::Filter target) {
138 const OatFile* oat_file = GetOatFile();
139 if (oat_file != nullptr) {
140 CompilerFilter::Filter current = oat_file->GetCompilerFilter();
141 return CompilerFilter::IsAsGoodAs(current, target);
142 }
143 return false;
144 }
145
OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target)146 bool OatFileAssistant::OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target) {
147 const OatFile* odex_file = GetOdexFile();
148 if (odex_file != nullptr) {
149 CompilerFilter::Filter current = odex_file->GetCompilerFilter();
150 return CompilerFilter::IsAsGoodAs(current, target);
151 }
152 return false;
153 }
154
GetDexOptNeeded(CompilerFilter::Filter target)155 OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target) {
156 bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
157
158 // See if the oat file is in good shape as is.
159 bool oat_okay = OatFileCompilerFilterIsOkay(target);
160 if (oat_okay) {
161 if (compilation_desired) {
162 if (OatFileIsUpToDate()) {
163 return kNoDexOptNeeded;
164 }
165 } else {
166 if (!OatFileIsOutOfDate()) {
167 return kNoDexOptNeeded;
168 }
169 }
170 }
171
172 // See if the odex file is in good shape as is.
173 bool odex_okay = OdexFileCompilerFilterIsOkay(target);
174 if (odex_okay) {
175 if (compilation_desired) {
176 if (OdexFileIsUpToDate()) {
177 return kNoDexOptNeeded;
178 }
179 } else {
180 if (!OdexFileIsOutOfDate()) {
181 return kNoDexOptNeeded;
182 }
183 }
184 }
185
186 // See if we can get an up-to-date file by running patchoat.
187 if (compilation_desired) {
188 if (odex_okay && OdexFileNeedsRelocation() && OdexFileHasPatchInfo()) {
189 return kPatchOatNeeded;
190 }
191
192 if (oat_okay && OatFileNeedsRelocation() && OatFileHasPatchInfo()) {
193 return kSelfPatchOatNeeded;
194 }
195 }
196
197 // We can only run dex2oat if there are original dex files.
198 return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded;
199 }
200
IsUpToDate()201 bool OatFileAssistant::IsUpToDate() {
202 return OatFileIsUpToDate() || OdexFileIsUpToDate();
203 }
204
205 OatFileAssistant::ResultOfAttemptToUpdate
MakeUpToDate(CompilerFilter::Filter target,std::string * error_msg)206 OatFileAssistant::MakeUpToDate(CompilerFilter::Filter target, std::string* error_msg) {
207 switch (GetDexOptNeeded(target)) {
208 case kNoDexOptNeeded: return kUpdateSucceeded;
209 case kDex2OatNeeded: return GenerateOatFile(target, error_msg);
210 case kPatchOatNeeded: return RelocateOatFile(OdexFileName(), error_msg);
211 case kSelfPatchOatNeeded: return RelocateOatFile(OatFileName(), error_msg);
212 }
213 UNREACHABLE();
214 }
215
GetBestOatFile()216 std::unique_ptr<OatFile> OatFileAssistant::GetBestOatFile() {
217 // The best oat files are, in descending order of bestness:
218 // 1. Properly relocated files. These may be opened executable.
219 // 2. Not out-of-date files that are already opened non-executable.
220 // 3. Not out-of-date files that we must reopen non-executable.
221
222 if (OatFileIsUpToDate()) {
223 oat_file_released_ = true;
224 return std::move(cached_oat_file_);
225 }
226
227 if (OdexFileIsUpToDate()) {
228 oat_file_released_ = true;
229 return std::move(cached_odex_file_);
230 }
231
232 VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
233 << " attempting to fall back to interpreting oat file instead.";
234
235 if (!OatFileIsOutOfDate() && !OatFileIsExecutable()) {
236 oat_file_released_ = true;
237 return std::move(cached_oat_file_);
238 }
239
240 if (!OdexFileIsOutOfDate() && !OdexFileIsExecutable()) {
241 oat_file_released_ = true;
242 return std::move(cached_odex_file_);
243 }
244
245 if (!OatFileIsOutOfDate()) {
246 load_executable_ = false;
247 ClearOatFileCache();
248 if (!OatFileIsOutOfDate()) {
249 CHECK(!OatFileIsExecutable());
250 oat_file_released_ = true;
251 return std::move(cached_oat_file_);
252 }
253 }
254
255 if (!OdexFileIsOutOfDate()) {
256 load_executable_ = false;
257 ClearOdexFileCache();
258 if (!OdexFileIsOutOfDate()) {
259 CHECK(!OdexFileIsExecutable());
260 oat_file_released_ = true;
261 return std::move(cached_odex_file_);
262 }
263 }
264
265 return std::unique_ptr<OatFile>();
266 }
267
LoadDexFiles(const OatFile & oat_file,const char * dex_location)268 std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
269 const OatFile& oat_file, const char* dex_location) {
270 std::vector<std::unique_ptr<const DexFile>> dex_files;
271
272 // Load the primary dex file.
273 std::string error_msg;
274 const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(
275 dex_location, nullptr, false);
276 if (oat_dex_file == nullptr) {
277 LOG(WARNING) << "Attempt to load out-of-date oat file "
278 << oat_file.GetLocation() << " for dex location " << dex_location;
279 return std::vector<std::unique_ptr<const DexFile>>();
280 }
281
282 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
283 if (dex_file.get() == nullptr) {
284 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
285 return std::vector<std::unique_ptr<const DexFile>>();
286 }
287 dex_files.push_back(std::move(dex_file));
288
289 // Load secondary multidex files
290 for (size_t i = 1; ; i++) {
291 std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location);
292 oat_dex_file = oat_file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
293 if (oat_dex_file == nullptr) {
294 // There are no more secondary dex files to load.
295 break;
296 }
297
298 dex_file = oat_dex_file->OpenDexFile(&error_msg);
299 if (dex_file.get() == nullptr) {
300 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
301 return std::vector<std::unique_ptr<const DexFile>>();
302 }
303 dex_files.push_back(std::move(dex_file));
304 }
305 return dex_files;
306 }
307
HasOriginalDexFiles()308 bool OatFileAssistant::HasOriginalDexFiles() {
309 // Ensure GetRequiredDexChecksum has been run so that
310 // has_original_dex_files_ is initialized. We don't care about the result of
311 // GetRequiredDexChecksum.
312 GetRequiredDexChecksum();
313 return has_original_dex_files_;
314 }
315
OdexFileName()316 const std::string* OatFileAssistant::OdexFileName() {
317 if (!cached_odex_file_name_attempted_) {
318 cached_odex_file_name_attempted_ = true;
319
320 std::string error_msg;
321 cached_odex_file_name_found_ = DexFilenameToOdexFilename(
322 dex_location_, isa_, &cached_odex_file_name_, &error_msg);
323 if (!cached_odex_file_name_found_) {
324 // If we can't figure out the odex file, we treat it as if the odex
325 // file was inaccessible.
326 LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
327 }
328 }
329 return cached_odex_file_name_found_ ? &cached_odex_file_name_ : nullptr;
330 }
331
OdexFileExists()332 bool OatFileAssistant::OdexFileExists() {
333 return GetOdexFile() != nullptr;
334 }
335
OdexFileStatus()336 OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() {
337 if (OdexFileIsOutOfDate()) {
338 return kOatOutOfDate;
339 }
340 if (OdexFileIsUpToDate()) {
341 return kOatUpToDate;
342 }
343 return kOatNeedsRelocation;
344 }
345
OdexFileIsOutOfDate()346 bool OatFileAssistant::OdexFileIsOutOfDate() {
347 if (!odex_file_is_out_of_date_attempted_) {
348 odex_file_is_out_of_date_attempted_ = true;
349 const OatFile* odex_file = GetOdexFile();
350 if (odex_file == nullptr) {
351 cached_odex_file_is_out_of_date_ = true;
352 } else {
353 cached_odex_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*odex_file);
354 }
355 }
356 return cached_odex_file_is_out_of_date_;
357 }
358
OdexFileNeedsRelocation()359 bool OatFileAssistant::OdexFileNeedsRelocation() {
360 return OdexFileStatus() == kOatNeedsRelocation;
361 }
362
OdexFileIsUpToDate()363 bool OatFileAssistant::OdexFileIsUpToDate() {
364 if (!odex_file_is_up_to_date_attempted_) {
365 odex_file_is_up_to_date_attempted_ = true;
366 const OatFile* odex_file = GetOdexFile();
367 if (odex_file == nullptr) {
368 cached_odex_file_is_up_to_date_ = false;
369 } else {
370 cached_odex_file_is_up_to_date_ = GivenOatFileIsUpToDate(*odex_file);
371 }
372 }
373 return cached_odex_file_is_up_to_date_;
374 }
375
OdexFileCompilerFilter()376 CompilerFilter::Filter OatFileAssistant::OdexFileCompilerFilter() {
377 const OatFile* odex_file = GetOdexFile();
378 CHECK(odex_file != nullptr);
379
380 return odex_file->GetCompilerFilter();
381 }
ArtFileName(const OatFile * oat_file) const382 std::string OatFileAssistant::ArtFileName(const OatFile* oat_file) const {
383 const std::string oat_file_location = oat_file->GetLocation();
384 // Replace extension with .art
385 const size_t last_ext = oat_file_location.find_last_of('.');
386 if (last_ext == std::string::npos) {
387 LOG(ERROR) << "No extension in oat file " << oat_file_location;
388 return std::string();
389 }
390 return oat_file_location.substr(0, last_ext) + ".art";
391 }
392
OatFileName()393 const std::string* OatFileAssistant::OatFileName() {
394 if (!cached_oat_file_name_attempted_) {
395 cached_oat_file_name_attempted_ = true;
396
397 // Compute the oat file name from the dex location.
398 // TODO: The oat file assistant should be the definitive place for
399 // determining the oat file name from the dex location, not
400 // GetDalvikCacheFilename.
401 std::string cache_dir = StringPrintf("%s%s",
402 DalvikCacheDirectory().c_str(), GetInstructionSetString(isa_));
403 std::string error_msg;
404 cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_.c_str(),
405 cache_dir.c_str(), &cached_oat_file_name_, &error_msg);
406 if (!cached_oat_file_name_found_) {
407 // If we can't determine the oat file name, we treat the oat file as
408 // inaccessible.
409 LOG(WARNING) << "Failed to determine oat file name for dex location "
410 << dex_location_ << ": " << error_msg;
411 }
412 }
413 return cached_oat_file_name_found_ ? &cached_oat_file_name_ : nullptr;
414 }
415
OatFileExists()416 bool OatFileAssistant::OatFileExists() {
417 return GetOatFile() != nullptr;
418 }
419
OatFileStatus()420 OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() {
421 if (OatFileIsOutOfDate()) {
422 return kOatOutOfDate;
423 }
424 if (OatFileIsUpToDate()) {
425 return kOatUpToDate;
426 }
427 return kOatNeedsRelocation;
428 }
429
OatFileIsOutOfDate()430 bool OatFileAssistant::OatFileIsOutOfDate() {
431 if (!oat_file_is_out_of_date_attempted_) {
432 oat_file_is_out_of_date_attempted_ = true;
433 const OatFile* oat_file = GetOatFile();
434 if (oat_file == nullptr) {
435 cached_oat_file_is_out_of_date_ = true;
436 } else {
437 cached_oat_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*oat_file);
438 }
439 }
440 return cached_oat_file_is_out_of_date_;
441 }
442
OatFileNeedsRelocation()443 bool OatFileAssistant::OatFileNeedsRelocation() {
444 return OatFileStatus() == kOatNeedsRelocation;
445 }
446
OatFileIsUpToDate()447 bool OatFileAssistant::OatFileIsUpToDate() {
448 if (!oat_file_is_up_to_date_attempted_) {
449 oat_file_is_up_to_date_attempted_ = true;
450 const OatFile* oat_file = GetOatFile();
451 if (oat_file == nullptr) {
452 cached_oat_file_is_up_to_date_ = false;
453 } else {
454 cached_oat_file_is_up_to_date_ = GivenOatFileIsUpToDate(*oat_file);
455 }
456 }
457 return cached_oat_file_is_up_to_date_;
458 }
459
OatFileCompilerFilter()460 CompilerFilter::Filter OatFileAssistant::OatFileCompilerFilter() {
461 const OatFile* oat_file = GetOatFile();
462 CHECK(oat_file != nullptr);
463
464 return oat_file->GetCompilerFilter();
465 }
466
GivenOatFileStatus(const OatFile & file)467 OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
468 // TODO: This could cause GivenOatFileIsOutOfDate to be called twice, which
469 // is more work than we need to do. If performance becomes a concern, and
470 // this method is actually called, this should be fixed.
471 if (GivenOatFileIsOutOfDate(file)) {
472 return kOatOutOfDate;
473 }
474 if (GivenOatFileIsUpToDate(file)) {
475 return kOatUpToDate;
476 }
477 return kOatNeedsRelocation;
478 }
479
GivenOatFileIsOutOfDate(const OatFile & file)480 bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
481 // Verify the dex checksum.
482 // Note: GetOatDexFile will return null if the dex checksum doesn't match
483 // what we provide, which verifies the primary dex checksum for us.
484 const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum();
485 const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(
486 dex_location_.c_str(), dex_checksum_pointer, false);
487 if (oat_dex_file == nullptr) {
488 return true;
489 }
490
491 // Verify the dex checksums for any secondary multidex files
492 for (size_t i = 1; ; i++) {
493 std::string secondary_dex_location
494 = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
495 const OatFile::OatDexFile* secondary_oat_dex_file
496 = file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
497 if (secondary_oat_dex_file == nullptr) {
498 // There are no more secondary dex files to check.
499 break;
500 }
501
502 std::string error_msg;
503 uint32_t expected_secondary_checksum = 0;
504 if (DexFile::GetChecksum(secondary_dex_location.c_str(),
505 &expected_secondary_checksum, &error_msg)) {
506 uint32_t actual_secondary_checksum
507 = secondary_oat_dex_file->GetDexFileLocationChecksum();
508 if (expected_secondary_checksum != actual_secondary_checksum) {
509 VLOG(oat) << "Dex checksum does not match for secondary dex: "
510 << secondary_dex_location
511 << ". Expected: " << expected_secondary_checksum
512 << ", Actual: " << actual_secondary_checksum;
513 return true;
514 }
515 } else {
516 // If we can't get the checksum for the secondary location, we assume
517 // the dex checksum is up to date for this and all other secondary dex
518 // files.
519 break;
520 }
521 }
522
523 CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
524 VLOG(oat) << "Compiler filter for " << file.GetLocation() << " is " << current_compiler_filter;
525
526 // Verify the image checksum
527 if (CompilerFilter::DependsOnImageChecksum(current_compiler_filter)) {
528 const ImageInfo* image_info = GetImageInfo();
529 if (image_info == nullptr) {
530 VLOG(oat) << "No image for oat image checksum to match against.";
531
532 if (HasOriginalDexFiles()) {
533 return true;
534 }
535
536 // If there is no original dex file to fall back to, grudgingly accept
537 // the oat file. This could technically lead to crashes, but there's no
538 // way we could find a better oat file to use for this dex location,
539 // and it's better than being stuck in a boot loop with no way out.
540 // The problem will hopefully resolve itself the next time the runtime
541 // starts up.
542 LOG(WARNING) << "Dex location " << dex_location_ << " does not seem to include dex file. "
543 << "Allow oat file use. This is potentially dangerous.";
544 } else if (file.GetOatHeader().GetImageFileLocationOatChecksum()
545 != GetCombinedImageChecksum()) {
546 VLOG(oat) << "Oat image checksum does not match image checksum.";
547 return true;
548 }
549 } else {
550 VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
551 }
552
553 // Verify the profile hasn't changed recently.
554 // TODO: Move this check to OatFileCompilerFilterIsOkay? Nothing bad should
555 // happen if we use an oat file compiled with an out-of-date profile.
556 if (CompilerFilter::DependsOnProfile(current_compiler_filter)) {
557 if (profile_changed_) {
558 VLOG(oat) << "The profile has changed recently.";
559 return true;
560 }
561 } else {
562 VLOG(oat) << "Profile check skipped for compiler filter " << current_compiler_filter;
563 }
564
565 // Everything looks good; the dex file is not out of date.
566 return false;
567 }
568
GivenOatFileNeedsRelocation(const OatFile & file)569 bool OatFileAssistant::GivenOatFileNeedsRelocation(const OatFile& file) {
570 return GivenOatFileStatus(file) == kOatNeedsRelocation;
571 }
572
GivenOatFileIsUpToDate(const OatFile & file)573 bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
574 if (GivenOatFileIsOutOfDate(file)) {
575 return false;
576 }
577
578 CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
579
580 if (CompilerFilter::IsBytecodeCompilationEnabled(current_compiler_filter)) {
581 if (!file.IsPic()) {
582 const ImageInfo* image_info = GetImageInfo();
583 if (image_info == nullptr) {
584 VLOG(oat) << "No image to check oat relocation against.";
585 return false;
586 }
587
588 // Verify the oat_data_begin recorded for the image in the oat file matches
589 // the actual oat_data_begin for boot.oat in the image.
590 const OatHeader& oat_header = file.GetOatHeader();
591 uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
592 if (oat_data_begin != image_info->oat_data_begin) {
593 VLOG(oat) << file.GetLocation() <<
594 ": Oat file image oat_data_begin (" << oat_data_begin << ")"
595 << " does not match actual image oat_data_begin ("
596 << image_info->oat_data_begin << ")";
597 return false;
598 }
599
600 // Verify the oat_patch_delta recorded for the image in the oat file matches
601 // the actual oat_patch_delta for the image.
602 int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
603 if (oat_patch_delta != image_info->patch_delta) {
604 VLOG(oat) << file.GetLocation() <<
605 ": Oat file image patch delta (" << oat_patch_delta << ")"
606 << " does not match actual image patch delta ("
607 << image_info->patch_delta << ")";
608 return false;
609 }
610 } else {
611 // Oat files compiled in PIC mode do not require relocation.
612 VLOG(oat) << "Oat relocation test skipped for PIC oat file";
613 }
614 } else {
615 VLOG(oat) << "Oat relocation test skipped for compiler filter " << current_compiler_filter;
616 }
617 return true;
618 }
619
620 OatFileAssistant::ResultOfAttemptToUpdate
RelocateOatFile(const std::string * input_file,std::string * error_msg)621 OatFileAssistant::RelocateOatFile(const std::string* input_file, std::string* error_msg) {
622 CHECK(error_msg != nullptr);
623
624 if (input_file == nullptr) {
625 *error_msg = "Patching of oat file for dex location " + dex_location_
626 + " not attempted because the input file name could not be determined.";
627 return kUpdateNotAttempted;
628 }
629 const std::string& input_file_name = *input_file;
630
631 if (OatFileName() == nullptr) {
632 *error_msg = "Patching of oat file for dex location " + dex_location_
633 + " not attempted because the oat file name could not be determined.";
634 return kUpdateNotAttempted;
635 }
636 const std::string& oat_file_name = *OatFileName();
637
638 const ImageInfo* image_info = GetImageInfo();
639 Runtime* runtime = Runtime::Current();
640 if (image_info == nullptr) {
641 *error_msg = "Patching of oat file " + oat_file_name
642 + " not attempted because no image location was found.";
643 return kUpdateNotAttempted;
644 }
645
646 if (!runtime->IsDex2OatEnabled()) {
647 *error_msg = "Patching of oat file " + oat_file_name
648 + " not attempted because dex2oat is disabled";
649 return kUpdateNotAttempted;
650 }
651
652 std::vector<std::string> argv;
653 argv.push_back(runtime->GetPatchoatExecutable());
654 argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(isa_)));
655 argv.push_back("--input-oat-file=" + input_file_name);
656 argv.push_back("--output-oat-file=" + oat_file_name);
657 argv.push_back("--patched-image-location=" + image_info->location);
658
659 std::string command_line(Join(argv, ' '));
660 if (!Exec(argv, error_msg)) {
661 // Manually delete the file. This ensures there is no garbage left over if
662 // the process unexpectedly died.
663 unlink(oat_file_name.c_str());
664 return kUpdateFailed;
665 }
666
667 // Mark that the oat file has changed and we should try to reload.
668 ClearOatFileCache();
669 return kUpdateSucceeded;
670 }
671
672 OatFileAssistant::ResultOfAttemptToUpdate
GenerateOatFile(CompilerFilter::Filter target,std::string * error_msg)673 OatFileAssistant::GenerateOatFile(CompilerFilter::Filter target, std::string* error_msg) {
674 CHECK(error_msg != nullptr);
675
676 Runtime* runtime = Runtime::Current();
677 if (!runtime->IsDex2OatEnabled()) {
678 *error_msg = "Generation of oat file for dex location " + dex_location_
679 + " not attempted because dex2oat is disabled.";
680 return kUpdateNotAttempted;
681 }
682
683 if (OatFileName() == nullptr) {
684 *error_msg = "Generation of oat file for dex location " + dex_location_
685 + " not attempted because the oat file name could not be determined.";
686 return kUpdateNotAttempted;
687 }
688 const std::string& oat_file_name = *OatFileName();
689
690 // dex2oat ignores missing dex files and doesn't report an error.
691 // Check explicitly here so we can detect the error properly.
692 // TODO: Why does dex2oat behave that way?
693 if (!OS::FileExists(dex_location_.c_str())) {
694 *error_msg = "Dex location " + dex_location_ + " does not exists.";
695 return kUpdateNotAttempted;
696 }
697
698 std::unique_ptr<File> oat_file;
699 oat_file.reset(OS::CreateEmptyFile(oat_file_name.c_str()));
700 if (oat_file.get() == nullptr) {
701 *error_msg = "Generation of oat file " + oat_file_name
702 + " not attempted because the oat file could not be created.";
703 return kUpdateNotAttempted;
704 }
705
706 if (fchmod(oat_file->Fd(), 0644) != 0) {
707 *error_msg = "Generation of oat file " + oat_file_name
708 + " not attempted because the oat file could not be made world readable.";
709 oat_file->Erase();
710 return kUpdateNotAttempted;
711 }
712
713 std::vector<std::string> args;
714 args.push_back("--dex-file=" + dex_location_);
715 args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
716 args.push_back("--oat-location=" + oat_file_name);
717 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(target));
718
719 if (!Dex2Oat(args, error_msg)) {
720 // Manually delete the file. This ensures there is no garbage left over if
721 // the process unexpectedly died.
722 oat_file->Erase();
723 unlink(oat_file_name.c_str());
724 return kUpdateFailed;
725 }
726
727 if (oat_file->FlushCloseOrErase() != 0) {
728 *error_msg = "Unable to close oat file " + oat_file_name;
729 unlink(oat_file_name.c_str());
730 return kUpdateFailed;
731 }
732
733 // Mark that the oat file has changed and we should try to reload.
734 ClearOatFileCache();
735 return kUpdateSucceeded;
736 }
737
Dex2Oat(const std::vector<std::string> & args,std::string * error_msg)738 bool OatFileAssistant::Dex2Oat(const std::vector<std::string>& args,
739 std::string* error_msg) {
740 Runtime* runtime = Runtime::Current();
741 std::string image_location = ImageLocation();
742 if (image_location.empty()) {
743 *error_msg = "No image location found for Dex2Oat.";
744 return false;
745 }
746
747 std::vector<std::string> argv;
748 argv.push_back(runtime->GetCompilerExecutable());
749 argv.push_back("--runtime-arg");
750 argv.push_back("-classpath");
751 argv.push_back("--runtime-arg");
752 std::string class_path = runtime->GetClassPathString();
753 if (class_path == "") {
754 class_path = OatFile::kSpecialSharedLibrary;
755 }
756 argv.push_back(class_path);
757 if (runtime->IsDebuggable()) {
758 argv.push_back("--debuggable");
759 }
760 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
761
762 if (!runtime->IsVerificationEnabled()) {
763 argv.push_back("--compiler-filter=verify-none");
764 }
765
766 if (runtime->MustRelocateIfPossible()) {
767 argv.push_back("--runtime-arg");
768 argv.push_back("-Xrelocate");
769 } else {
770 argv.push_back("--runtime-arg");
771 argv.push_back("-Xnorelocate");
772 }
773
774 if (!kIsTargetBuild) {
775 argv.push_back("--host");
776 }
777
778 argv.push_back("--boot-image=" + image_location);
779
780 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
781 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
782
783 argv.insert(argv.end(), args.begin(), args.end());
784
785 std::string command_line(Join(argv, ' '));
786 return Exec(argv, error_msg);
787 }
788
DexFilenameToOdexFilename(const std::string & location,InstructionSet isa,std::string * odex_filename,std::string * error_msg)789 bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
790 InstructionSet isa, std::string* odex_filename, std::string* error_msg) {
791 CHECK(odex_filename != nullptr);
792 CHECK(error_msg != nullptr);
793
794 // The odex file name is formed by replacing the dex_location extension with
795 // .odex and inserting an oat/<isa> directory. For example:
796 // location = /foo/bar/baz.jar
797 // odex_location = /foo/bar/oat/<isa>/baz.odex
798
799 // Find the directory portion of the dex location and add the oat/<isa>
800 // directory.
801 size_t pos = location.rfind('/');
802 if (pos == std::string::npos) {
803 *error_msg = "Dex location " + location + " has no directory.";
804 return false;
805 }
806 std::string dir = location.substr(0, pos+1);
807 dir += "oat/" + std::string(GetInstructionSetString(isa));
808
809 // Find the file portion of the dex location.
810 std::string file;
811 if (pos == std::string::npos) {
812 file = location;
813 } else {
814 file = location.substr(pos+1);
815 }
816
817 // Get the base part of the file without the extension.
818 pos = file.rfind('.');
819 if (pos == std::string::npos) {
820 *error_msg = "Dex location " + location + " has no extension.";
821 return false;
822 }
823 std::string base = file.substr(0, pos);
824
825 *odex_filename = dir + "/" + base + ".odex";
826 return true;
827 }
828
DalvikCacheDirectory()829 std::string OatFileAssistant::DalvikCacheDirectory() {
830 // Note: We don't cache this, because it will only be called once by
831 // OatFileName.
832
833 // TODO: The work done in GetDalvikCache is overkill for what we need.
834 // Ideally a new API for getting the DalvikCacheDirectory the way we want
835 // (without existence testing, creation, or death) is provided with the rest
836 // of the GetDalvikCache family of functions. Until such an API is in place,
837 // we use GetDalvikCache to avoid duplicating the logic for determining the
838 // dalvik cache directory.
839 std::string result;
840 bool have_android_data;
841 bool dalvik_cache_exists;
842 bool is_global_cache;
843 GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache);
844 return result;
845 }
846
ImageLocation()847 std::string OatFileAssistant::ImageLocation() {
848 Runtime* runtime = Runtime::Current();
849 const std::vector<gc::space::ImageSpace*>& image_spaces =
850 runtime->GetHeap()->GetBootImageSpaces();
851 if (image_spaces.empty()) {
852 return "";
853 }
854 return image_spaces[0]->GetImageLocation();
855 }
856
GetRequiredDexChecksum()857 const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
858 if (!required_dex_checksum_attempted_) {
859 required_dex_checksum_attempted_ = true;
860 required_dex_checksum_found_ = false;
861 std::string error_msg;
862 if (DexFile::GetChecksum(dex_location_.c_str(), &cached_required_dex_checksum_, &error_msg)) {
863 required_dex_checksum_found_ = true;
864 has_original_dex_files_ = true;
865 } else {
866 // This can happen if the original dex file has been stripped from the
867 // apk.
868 VLOG(oat) << "OatFileAssistant: " << error_msg;
869 has_original_dex_files_ = false;
870
871 // Get the checksum from the odex if we can.
872 const OatFile* odex_file = GetOdexFile();
873 if (odex_file != nullptr) {
874 const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
875 dex_location_.c_str(), nullptr, false);
876 if (odex_dex_file != nullptr) {
877 cached_required_dex_checksum_ = odex_dex_file->GetDexFileLocationChecksum();
878 required_dex_checksum_found_ = true;
879 }
880 }
881 }
882 }
883 return required_dex_checksum_found_ ? &cached_required_dex_checksum_ : nullptr;
884 }
885
GetOdexFile()886 const OatFile* OatFileAssistant::GetOdexFile() {
887 CHECK(!oat_file_released_) << "OdexFile called after oat file released.";
888 if (!odex_file_load_attempted_) {
889 odex_file_load_attempted_ = true;
890 if (OdexFileName() != nullptr) {
891 const std::string& odex_file_name = *OdexFileName();
892 std::string error_msg;
893 cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
894 odex_file_name.c_str(),
895 nullptr,
896 nullptr,
897 load_executable_,
898 /*low_4gb*/false,
899 dex_location_.c_str(),
900 &error_msg));
901 if (cached_odex_file_.get() == nullptr) {
902 VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
903 << odex_file_name << ": " << error_msg;
904 }
905 }
906 }
907 return cached_odex_file_.get();
908 }
909
OdexFileIsExecutable()910 bool OatFileAssistant::OdexFileIsExecutable() {
911 const OatFile* odex_file = GetOdexFile();
912 return (odex_file != nullptr && odex_file->IsExecutable());
913 }
914
OdexFileHasPatchInfo()915 bool OatFileAssistant::OdexFileHasPatchInfo() {
916 const OatFile* odex_file = GetOdexFile();
917 return (odex_file != nullptr && odex_file->HasPatchInfo());
918 }
919
ClearOdexFileCache()920 void OatFileAssistant::ClearOdexFileCache() {
921 odex_file_load_attempted_ = false;
922 cached_odex_file_.reset();
923 odex_file_is_out_of_date_attempted_ = false;
924 odex_file_is_up_to_date_attempted_ = false;
925 }
926
GetOatFile()927 const OatFile* OatFileAssistant::GetOatFile() {
928 CHECK(!oat_file_released_) << "OatFile called after oat file released.";
929 if (!oat_file_load_attempted_) {
930 oat_file_load_attempted_ = true;
931 if (OatFileName() != nullptr) {
932 const std::string& oat_file_name = *OatFileName();
933 std::string error_msg;
934 cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
935 oat_file_name.c_str(),
936 nullptr,
937 nullptr,
938 load_executable_,
939 /*low_4gb*/false,
940 dex_location_.c_str(),
941 &error_msg));
942 if (cached_oat_file_.get() == nullptr) {
943 VLOG(oat) << "OatFileAssistant test for existing oat file "
944 << oat_file_name << ": " << error_msg;
945 }
946 }
947 }
948 return cached_oat_file_.get();
949 }
950
OatFileIsExecutable()951 bool OatFileAssistant::OatFileIsExecutable() {
952 const OatFile* oat_file = GetOatFile();
953 return (oat_file != nullptr && oat_file->IsExecutable());
954 }
955
OatFileHasPatchInfo()956 bool OatFileAssistant::OatFileHasPatchInfo() {
957 const OatFile* oat_file = GetOatFile();
958 return (oat_file != nullptr && oat_file->HasPatchInfo());
959 }
960
ClearOatFileCache()961 void OatFileAssistant::ClearOatFileCache() {
962 oat_file_load_attempted_ = false;
963 cached_oat_file_.reset();
964 oat_file_is_out_of_date_attempted_ = false;
965 oat_file_is_up_to_date_attempted_ = false;
966 }
967
GetImageInfo()968 const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
969 if (!image_info_load_attempted_) {
970 image_info_load_attempted_ = true;
971
972 Runtime* runtime = Runtime::Current();
973 std::vector<gc::space::ImageSpace*> image_spaces = runtime->GetHeap()->GetBootImageSpaces();
974 if (!image_spaces.empty()) {
975 cached_image_info_.location = image_spaces[0]->GetImageLocation();
976
977 if (isa_ == kRuntimeISA) {
978 const ImageHeader& image_header = image_spaces[0]->GetImageHeader();
979 cached_image_info_.oat_checksum = image_header.GetOatChecksum();
980 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(
981 image_header.GetOatDataBegin());
982 cached_image_info_.patch_delta = image_header.GetPatchDelta();
983 } else {
984 std::unique_ptr<ImageHeader> image_header(
985 gc::space::ImageSpace::ReadImageHeaderOrDie(cached_image_info_.location.c_str(), isa_));
986 cached_image_info_.oat_checksum = image_header->GetOatChecksum();
987 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(
988 image_header->GetOatDataBegin());
989 cached_image_info_.patch_delta = image_header->GetPatchDelta();
990 }
991 }
992 image_info_load_succeeded_ = (!image_spaces.empty());
993
994 combined_image_checksum_ = CalculateCombinedImageChecksum(isa_);
995 }
996 return image_info_load_succeeded_ ? &cached_image_info_ : nullptr;
997 }
998
999 // TODO: Use something better than xor.
CalculateCombinedImageChecksum(InstructionSet isa)1000 uint32_t OatFileAssistant::CalculateCombinedImageChecksum(InstructionSet isa) {
1001 uint32_t checksum = 0;
1002 std::vector<gc::space::ImageSpace*> image_spaces =
1003 Runtime::Current()->GetHeap()->GetBootImageSpaces();
1004 if (isa == kRuntimeISA) {
1005 for (gc::space::ImageSpace* image_space : image_spaces) {
1006 checksum ^= image_space->GetImageHeader().GetOatChecksum();
1007 }
1008 } else {
1009 for (gc::space::ImageSpace* image_space : image_spaces) {
1010 std::string location = image_space->GetImageLocation();
1011 std::unique_ptr<ImageHeader> image_header(
1012 gc::space::ImageSpace::ReadImageHeaderOrDie(location.c_str(), isa));
1013 checksum ^= image_header->GetOatChecksum();
1014 }
1015 }
1016 return checksum;
1017 }
1018
GetCombinedImageChecksum()1019 uint32_t OatFileAssistant::GetCombinedImageChecksum() {
1020 if (!image_info_load_attempted_) {
1021 GetImageInfo();
1022 }
1023 return combined_image_checksum_;
1024 }
1025
OpenImageSpace(const OatFile * oat_file)1026 gc::space::ImageSpace* OatFileAssistant::OpenImageSpace(const OatFile* oat_file) {
1027 DCHECK(oat_file != nullptr);
1028 std::string art_file = ArtFileName(oat_file);
1029 if (art_file.empty()) {
1030 return nullptr;
1031 }
1032 std::string error_msg;
1033 ScopedObjectAccess soa(Thread::Current());
1034 gc::space::ImageSpace* ret = gc::space::ImageSpace::CreateFromAppImage(art_file.c_str(),
1035 oat_file,
1036 &error_msg);
1037 if (ret == nullptr && (VLOG_IS_ON(image) || OS::FileExists(art_file.c_str()))) {
1038 LOG(INFO) << "Failed to open app image " << art_file.c_str() << " " << error_msg;
1039 }
1040 return ret;
1041 }
1042
1043 } // namespace art
1044
1045