blob: d92f59bde66d408055b5ccac850a0b3ea514bef8 [file] [log] [blame]
Richard Uhler66d874d2015-01-15 09:37:19 -08001/*
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 "class_linker.h"
34#include "gc/heap.h"
35#include "gc/space/image_space.h"
36#include "image.h"
37#include "oat.h"
38#include "os.h"
39#include "profiler.h"
40#include "runtime.h"
41#include "ScopedFd.h"
42#include "utils.h"
43
44namespace art {
45
46OatFileAssistant::OatFileAssistant(const char* dex_location,
47 const InstructionSet isa,
48 bool load_executable)
49 : OatFileAssistant(dex_location, nullptr, isa, load_executable, nullptr) { }
50
51OatFileAssistant::OatFileAssistant(const char* dex_location,
52 const char* oat_location,
53 const InstructionSet isa,
54 bool load_executable)
55 : OatFileAssistant(dex_location, oat_location, isa, load_executable, nullptr) { }
56
57OatFileAssistant::OatFileAssistant(const char* dex_location,
58 const InstructionSet isa,
59 bool load_executable,
60 const char* package_name)
61 : OatFileAssistant(dex_location, nullptr, isa, load_executable, package_name) { }
62
63OatFileAssistant::OatFileAssistant(const char* dex_location,
64 const char* oat_location,
65 const InstructionSet isa,
66 bool load_executable,
67 const char* package_name)
68 : dex_location_(dex_location), isa_(isa),
69 package_name_(package_name), load_executable_(load_executable) {
70 if (load_executable_ && isa != kRuntimeISA) {
71 LOG(WARNING) << "OatFileAssistant: Load executable specified, "
72 << "but isa is not kRuntimeISA. Will not attempt to load executable.";
73 load_executable_ = false;
74 }
75
76 // If the user gave a target oat location, save that as the cached oat
77 // location now so we won't try to construct the default location later.
78 if (oat_location != nullptr) {
79 cached_oat_file_name_ = std::string(oat_location);
80 cached_oat_file_name_attempted_ = true;
81 cached_oat_file_name_found_ = true;
82 }
83
84 // If there is no package name given, we will not be able to find any
85 // profiles associated with this dex location. Preemptively mark that to
86 // be the case, rather than trying to find and load the profiles later.
87 // Similarly, if profiling is disabled.
88 if (package_name == nullptr
89 || !Runtime::Current()->GetProfilerOptions().IsEnabled()) {
90 profile_load_attempted_ = true;
91 profile_load_succeeded_ = false;
92 old_profile_load_attempted_ = true;
93 old_profile_load_succeeded_ = false;
94 }
95}
96
97OatFileAssistant::~OatFileAssistant() {
98 // Clean up the lock file.
99 if (lock_file_.get() != nullptr) {
100 lock_file_->Erase();
101 TEMP_FAILURE_RETRY(unlink(lock_file_->GetPath().c_str()));
102 }
103}
104
105bool OatFileAssistant::IsInBootClassPath() {
106 // Note: We check the current boot class path, regardless of the ISA
107 // specified by the user. This is okay, because the boot class path should
108 // be the same for all ISAs.
109 // TODO: Can we verify the boot class path is the same for all ISAs?
110 Runtime* runtime = Runtime::Current();
111 ClassLinker* class_linker = runtime->GetClassLinker();
112 const auto& boot_class_path = class_linker->GetBootClassPath();
113 for (size_t i = 0; i < boot_class_path.size(); i++) {
114 if (boot_class_path[i]->GetLocation() == std::string(dex_location_)) {
115 VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path";
116 return true;
117 }
118 }
119 return false;
120}
121
122bool OatFileAssistant::Lock(std::string* error_msg) {
123 CHECK(error_msg != nullptr);
124 CHECK(lock_file_.get() == nullptr) << "OatFileAssistant::Lock already acquired";
125
126 if (OatFileName() == nullptr) {
127 *error_msg = "Failed to determine lock file";
128 return false;
129 }
130 std::string lock_file_name = *OatFileName() + ".flock";
131
132 lock_file_.reset(OS::CreateEmptyFile(lock_file_name.c_str()));
133 if (lock_file_.get() == nullptr) {
134 *error_msg = "Failed to create lock file " + lock_file_name;
135 return false;
136 }
137
138 if (!flock_.Init(lock_file_.get(), error_msg)) {
139 TEMP_FAILURE_RETRY(unlink(lock_file_name.c_str()));
140 return false;
141 }
142 return true;
143}
144
145OatFileAssistant::Status OatFileAssistant::GetStatus() {
146 // TODO: If the profiling code is ever restored, it's worth considering
147 // whether we should check to see if the profile is out of date here.
148
149 if (OdexFileIsOutOfDate()) {
150 // The DEX file is not pre-compiled.
151 // TODO: What if the oat file is not out of date? Could we relocate it
152 // from itself?
153 return OatFileIsUpToDate() ? kUpToDate : kOutOfDate;
154 } else {
155 // The DEX file is pre-compiled. If the oat file isn't up to date, we can
156 // patch the pre-compiled version rather than recompiling.
157 if (OatFileIsUpToDate() || OdexFileIsUpToDate()) {
158 return kUpToDate;
159 } else {
160 return kNeedsRelocation;
161 }
162 }
163}
164
165bool OatFileAssistant::MakeUpToDate(std::string* error_msg) {
166 switch (GetStatus()) {
167 case kUpToDate: return true;
168 case kNeedsRelocation: return RelocateOatFile(error_msg);
169 case kOutOfDate: return GenerateOatFile(error_msg);
170 }
171 UNREACHABLE();
172}
173
174std::unique_ptr<OatFile> OatFileAssistant::GetBestOatFile() {
175 if (OatFileIsUpToDate()) {
176 oat_file_released_ = true;
177 return std::move(cached_oat_file_);
178 }
179
180 if (OdexFileIsUpToDate()) {
181 oat_file_released_ = true;
182 return std::move(cached_odex_file_);
183 }
184
185 if (load_executable_) {
186 VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
187 << " attempting to fall back to interpreting oat file instead.";
188
189 if (!OatFileIsOutOfDate()) {
190 load_executable_ = false;
191 ClearOatFileCache();
192 if (!OatFileIsOutOfDate()) {
193 oat_file_released_ = true;
194 return std::move(cached_oat_file_);
195 }
196 }
197
198 if (!OdexFileIsOutOfDate()) {
199 load_executable_ = false;
200 ClearOdexFileCache();
201 if (!OdexFileIsOutOfDate()) {
202 oat_file_released_ = true;
203 return std::move(cached_odex_file_);
204 }
205 }
206 }
207
208 return std::unique_ptr<OatFile>();
209}
210
211std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
212 const OatFile& oat_file, const char* dex_location) {
213 std::vector<std::unique_ptr<const DexFile>> dex_files;
214
215 // Load the primary dex file.
216 std::string error_msg;
217 const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(
218 dex_location, nullptr, false);
219 if (oat_dex_file == nullptr) {
220 LOG(WARNING) << "Attempt to load out-of-date oat file "
221 << oat_file.GetLocation() << " for dex location " << dex_location;
222 return std::vector<std::unique_ptr<const DexFile>>();
223 }
224
225 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
226 if (dex_file.get() == nullptr) {
227 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
228 return std::vector<std::unique_ptr<const DexFile>>();
229 }
230 dex_files.push_back(std::move(dex_file));
231
232 // Load secondary multidex files
233 for (int i = 1; ; i++) {
234 std::string secondary_dex_location = DexFile::GetMultiDexClassesDexName(i, dex_location);
235 oat_dex_file = oat_file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
236 if (oat_dex_file == NULL) {
237 // There are no more secondary dex files to load.
238 break;
239 }
240
241 dex_file = oat_dex_file->OpenDexFile(&error_msg);
242 if (dex_file.get() == nullptr) {
243 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
244 return std::vector<std::unique_ptr<const DexFile>>();
245 }
246 dex_files.push_back(std::move(dex_file));
247 }
248 return dex_files;
249}
250
251const std::string* OatFileAssistant::OdexFileName() {
252 if (!cached_odex_file_name_attempted_) {
253 CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
254 cached_odex_file_name_attempted_ = true;
255
256 std::string error_msg;
257 cached_odex_file_name_found_ = DexFilenameToOdexFilename(
258 dex_location_, isa_, &cached_odex_file_name_, &error_msg);
259 if (!cached_odex_file_name_found_) {
260 // If we can't figure out the odex file, we treat it as if the odex
261 // file was inaccessible.
262 LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
263 }
264 }
265 return cached_odex_file_name_found_ ? &cached_odex_file_name_ : nullptr;
266}
267
268bool OatFileAssistant::OdexFileExists() {
269 return GetOdexFile() != nullptr;
270}
271
272OatFileAssistant::Status OatFileAssistant::OdexFileStatus() {
273 if (OdexFileIsOutOfDate()) {
274 return kOutOfDate;
275 }
276 if (OdexFileIsUpToDate()) {
277 return kUpToDate;
278 }
279 return kNeedsRelocation;
280}
281
282bool OatFileAssistant::OdexFileIsOutOfDate() {
283 if (!odex_file_is_out_of_date_attempted_) {
284 odex_file_is_out_of_date_attempted_ = true;
285 const OatFile* odex_file = GetOdexFile();
286 if (odex_file == nullptr) {
287 cached_odex_file_is_out_of_date_ = true;
288 } else {
289 cached_odex_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*odex_file);
290 }
291 }
292 return cached_odex_file_is_out_of_date_;
293}
294
295bool OatFileAssistant::OdexFileNeedsRelocation() {
296 return OdexFileStatus() == kNeedsRelocation;
297}
298
299bool OatFileAssistant::OdexFileIsUpToDate() {
300 if (!odex_file_is_up_to_date_attempted_) {
301 odex_file_is_up_to_date_attempted_ = true;
302 const OatFile* odex_file = GetOdexFile();
303 if (odex_file == nullptr) {
304 cached_odex_file_is_up_to_date_ = false;
305 } else {
306 cached_odex_file_is_up_to_date_ = GivenOatFileIsUpToDate(*odex_file);
307 }
308 }
309 return cached_odex_file_is_up_to_date_;
310}
311
312const std::string* OatFileAssistant::OatFileName() {
313 if (!cached_oat_file_name_attempted_) {
314 cached_oat_file_name_attempted_ = true;
315
316 // Compute the oat file name from the dex location.
317 CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
318
319 // TODO: The oat file assistant should be the definitive place for
320 // determining the oat file name from the dex location, not
321 // GetDalvikCacheFilename.
322 std::string cache_dir = StringPrintf("%s%s",
323 DalvikCacheDirectory().c_str(), GetInstructionSetString(isa_));
324 std::string error_msg;
325 cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_,
326 cache_dir.c_str(), &cached_oat_file_name_, &error_msg);
327 if (!cached_oat_file_name_found_) {
328 // If we can't determine the oat file name, we treat the oat file as
329 // inaccessible.
330 LOG(WARNING) << "Failed to determine oat file name for dex location "
331 << dex_location_ << ": " << error_msg;
332 }
333 }
334 return cached_oat_file_name_found_ ? &cached_oat_file_name_ : nullptr;
335}
336
337bool OatFileAssistant::OatFileExists() {
338 return GetOatFile() != nullptr;
339}
340
341OatFileAssistant::Status OatFileAssistant::OatFileStatus() {
342 if (OatFileIsOutOfDate()) {
343 return kOutOfDate;
344 }
345 if (OatFileIsUpToDate()) {
346 return kUpToDate;
347 }
348 return kNeedsRelocation;
349}
350
351bool OatFileAssistant::OatFileIsOutOfDate() {
352 if (!oat_file_is_out_of_date_attempted_) {
353 oat_file_is_out_of_date_attempted_ = true;
354 const OatFile* oat_file = GetOatFile();
355 if (oat_file == nullptr) {
356 cached_oat_file_is_out_of_date_ = true;
357 } else {
358 cached_oat_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*oat_file);
359 }
360 }
361 return cached_oat_file_is_out_of_date_;
362}
363
364bool OatFileAssistant::OatFileNeedsRelocation() {
365 return OatFileStatus() == kNeedsRelocation;
366}
367
368bool OatFileAssistant::OatFileIsUpToDate() {
369 if (!oat_file_is_up_to_date_attempted_) {
370 oat_file_is_up_to_date_attempted_ = true;
371 const OatFile* oat_file = GetOatFile();
372 if (oat_file == nullptr) {
373 cached_oat_file_is_up_to_date_ = false;
374 } else {
375 cached_oat_file_is_up_to_date_ = GivenOatFileIsUpToDate(*oat_file);
376 }
377 }
378 return cached_oat_file_is_up_to_date_;
379}
380
381OatFileAssistant::Status OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
382 // TODO: This could cause GivenOatFileIsOutOfDate to be called twice, which
383 // is more work than we need to do. If performance becomes a concern, and
384 // this method is actually called, this should be fixed.
385 if (GivenOatFileIsOutOfDate(file)) {
386 return kOutOfDate;
387 }
388 if (GivenOatFileIsUpToDate(file)) {
389 return kUpToDate;
390 }
391 return kNeedsRelocation;
392}
393
394bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
395 // Verify the dex checksum.
396 // Note: GetOatDexFile will return NULL if the dex checksum doesn't match
397 // what we provide, which verifies the primary dex checksum for us.
398 const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum();
399 const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(
400 dex_location_, dex_checksum_pointer, false);
401 if (oat_dex_file == NULL) {
402 return true;
403 }
404
405 // Verify the dex checksums for any secondary multidex files
406 for (int i = 1; ; i++) {
407 std::string secondary_dex_location
408 = DexFile::GetMultiDexClassesDexName(i, dex_location_);
409 const OatFile::OatDexFile* secondary_oat_dex_file
410 = file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
411 if (secondary_oat_dex_file == NULL) {
412 // There are no more secondary dex files to check.
413 break;
414 }
415
416 std::string error_msg;
417 uint32_t expected_secondary_checksum = 0;
418 if (DexFile::GetChecksum(secondary_dex_location.c_str(),
419 &expected_secondary_checksum, &error_msg)) {
420 uint32_t actual_secondary_checksum
421 = secondary_oat_dex_file->GetDexFileLocationChecksum();
422 if (expected_secondary_checksum != actual_secondary_checksum) {
423 VLOG(oat) << "Dex checksum does not match for secondary dex: "
424 << secondary_dex_location
425 << ". Expected: " << expected_secondary_checksum
426 << ", Actual: " << actual_secondary_checksum;
427 return false;
428 }
429 } else {
430 // If we can't get the checksum for the secondary location, we assume
431 // the dex checksum is up to date for this and all other secondary dex
432 // files.
433 break;
434 }
435 }
436
437 // Verify the image checksum
438 const ImageInfo* image_info = GetImageInfo();
439 if (image_info == nullptr) {
440 VLOG(oat) << "No image for oat image checksum to match against.";
441 return true;
442 }
443
444 if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) {
445 VLOG(oat) << "Oat image checksum does not match image checksum.";
446 return true;
447 }
448
449 // The checksums are all good; the dex file is not out of date.
450 return false;
451}
452
453bool OatFileAssistant::GivenOatFileNeedsRelocation(const OatFile& file) {
454 return GivenOatFileStatus(file) == kNeedsRelocation;
455}
456
457bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
458 if (GivenOatFileIsOutOfDate(file)) {
459 return false;
460 }
461
462 if (file.IsPic()) {
463 return true;
464 }
465
466 const ImageInfo* image_info = GetImageInfo();
467 if (image_info == nullptr) {
468 VLOG(oat) << "No image for to check oat relocation against.";
469 return false;
470 }
471
472 // Verify the oat_data_begin recorded for the image in the oat file matches
473 // the actual oat_data_begin for boot.oat in the image.
474 const OatHeader& oat_header = file.GetOatHeader();
475 uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
476 if (oat_data_begin != image_info->oat_data_begin) {
477 VLOG(oat) << file.GetLocation() <<
478 ": Oat file image oat_data_begin (" << oat_data_begin << ")"
479 << " does not match actual image oat_data_begin ("
480 << image_info->oat_data_begin << ")";
481 return false;
482 }
483
484 // Verify the oat_patch_delta recorded for the image in the oat file matches
485 // the actual oat_patch_delta for the image.
486 int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
487 if (oat_patch_delta != image_info->patch_delta) {
488 VLOG(oat) << file.GetLocation() <<
489 ": Oat file image patch delta (" << oat_patch_delta << ")"
490 << " does not match actual image patch delta ("
491 << image_info->patch_delta << ")";
492 return false;
493 }
494 return true;
495}
496
497bool OatFileAssistant::ProfileExists() {
498 return GetProfile() != nullptr;
499}
500
501bool OatFileAssistant::OldProfileExists() {
502 return GetOldProfile() != nullptr;
503}
504
505// TODO: The IsProfileChangeSignificant implementation was copied from likely
506// bit-rotted code.
507bool OatFileAssistant::IsProfileChangeSignificant() {
508 ProfileFile* profile = GetProfile();
509 if (profile == nullptr) {
510 return false;
511 }
512
513 ProfileFile* old_profile = GetOldProfile();
514 if (old_profile == nullptr) {
515 return false;
516 }
517
518 // TODO: The following code to compare two profile files should live with
519 // the rest of the profiler code, not the oat file assistant code.
520
521 // A change in profile is considered significant if X% (change_thr property)
522 // of the top K% (compile_thr property) samples has changed.
523 const ProfilerOptions& options = Runtime::Current()->GetProfilerOptions();
524 const double top_k_threshold = options.GetTopKThreshold();
525 const double change_threshold = options.GetTopKChangeThreshold();
526 std::set<std::string> top_k, old_top_k;
527 profile->GetTopKSamples(top_k, top_k_threshold);
528 old_profile->GetTopKSamples(old_top_k, top_k_threshold);
529 std::set<std::string> diff;
530 std::set_difference(top_k.begin(), top_k.end(), old_top_k.begin(),
531 old_top_k.end(), std::inserter(diff, diff.end()));
532
533 // TODO: consider using the usedPercentage instead of the plain diff count.
534 double change_percent = 100.0 * static_cast<double>(diff.size())
535 / static_cast<double>(top_k.size());
536 std::set<std::string>::iterator end = diff.end();
537 for (std::set<std::string>::iterator it = diff.begin(); it != end; it++) {
538 VLOG(oat) << "Profile new in topK: " << *it;
539 }
540
541 if (change_percent > change_threshold) {
542 VLOG(oat) << "Oat File Assistant: Profile for " << dex_location_
543 << "has changed significantly: (top "
544 << top_k_threshold << "% samples changed in proportion of "
545 << change_percent << "%)";
546 return true;
547 }
548 return false;
549}
550
551// TODO: The CopyProfileFile implementation was copied from likely bit-rotted
552// code.
553void OatFileAssistant::CopyProfileFile() {
554 if (!ProfileExists()) {
555 return;
556 }
557
558 std::string profile_name = ProfileFileName();
559 std::string old_profile_name = OldProfileFileName();
560
561 ScopedFd src(open(old_profile_name.c_str(), O_RDONLY));
562 if (src.get() == -1) {
563 PLOG(WARNING) << "Failed to open profile file " << old_profile_name
564 << ". My uid:gid is " << getuid() << ":" << getgid();
565 return;
566 }
567
568 struct stat stat_src;
569 if (fstat(src.get(), &stat_src) == -1) {
570 PLOG(WARNING) << "Failed to get stats for profile file " << old_profile_name
571 << ". My uid:gid is " << getuid() << ":" << getgid();
572 return;
573 }
574
575 // Create the copy with rw------- (only accessible by system)
576 ScopedFd dst(open(profile_name.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0600));
577 if (dst.get() == -1) {
578 PLOG(WARNING) << "Failed to create/write prev profile file " << profile_name
579 << ". My uid:gid is " << getuid() << ":" << getgid();
580 return;
581 }
582
583#ifdef __linux__
584 if (sendfile(dst.get(), src.get(), nullptr, stat_src.st_size) == -1) {
585#else
586 off_t len;
587 if (sendfile(dst.get(), src.get(), 0, &len, nullptr, 0) == -1) {
588#endif
589 PLOG(WARNING) << "Failed to copy profile file " << old_profile_name
590 << " to " << profile_name << ". My uid:gid is " << getuid()
591 << ":" << getgid();
592 }
593}
594
595bool OatFileAssistant::RelocateOatFile(std::string* error_msg) {
596 CHECK(error_msg != nullptr);
597
598 if (OdexFileName() == nullptr) {
599 *error_msg = "Patching of oat file for dex location "
600 + std::string(dex_location_)
601 + " not attempted because the odex file name could not be determined.";
602 return false;
603 }
604 const std::string& odex_file_name = *OdexFileName();
605
606 if (OatFileName() == nullptr) {
607 *error_msg = "Patching of oat file for dex location "
608 + std::string(dex_location_)
609 + " not attempted because the oat file name could not be determined.";
610 return false;
611 }
612 const std::string& oat_file_name = *OatFileName();
613
614 const ImageInfo* image_info = GetImageInfo();
615 Runtime* runtime = Runtime::Current();
616 if (image_info == nullptr) {
617 *error_msg = "Patching of oat file " + oat_file_name
618 + " not attempted because no image location was found.";
619 return false;
620 }
621
622 if (!runtime->IsDex2OatEnabled()) {
623 *error_msg = "Patching of oat file " + oat_file_name
624 + " not attempted because dex2oat is disabled";
625 return false;
626 }
627
628 std::vector<std::string> argv;
629 argv.push_back(runtime->GetPatchoatExecutable());
630 argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(isa_)));
631 argv.push_back("--input-oat-file=" + odex_file_name);
632 argv.push_back("--output-oat-file=" + oat_file_name);
633 argv.push_back("--patched-image-location=" + image_info->location);
634
635 std::string command_line(Join(argv, ' '));
636 if (!Exec(argv, error_msg)) {
637 // Manually delete the file. This ensures there is no garbage left over if
638 // the process unexpectedly died.
639 TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
640 return false;
641 }
642
643 // Mark that the oat file has changed and we should try to reload.
644 ClearOatFileCache();
645 return true;
646}
647
648bool OatFileAssistant::GenerateOatFile(std::string* error_msg) {
649 CHECK(error_msg != nullptr);
650
651 if (OatFileName() == nullptr) {
652 *error_msg = "Generation of oat file for dex location "
653 + std::string(dex_location_)
654 + " not attempted because the oat file name could not be determined.";
655 return false;
656 }
657 const std::string& oat_file_name = *OatFileName();
658
659 Runtime* runtime = Runtime::Current();
660 if (!runtime->IsDex2OatEnabled()) {
661 *error_msg = "Generation of oat file " + oat_file_name
662 + " not attempted because dex2oat is disabled";
663 return false;
664 }
665
666 std::vector<std::string> args;
667 args.push_back("--dex-file=" + std::string(dex_location_));
668 args.push_back("--oat-file=" + oat_file_name);
669
670 // dex2oat ignores missing dex files and doesn't report an error.
671 // Check explicitly here so we can detect the error properly.
672 // TODO: Why does dex2oat behave that way?
673 if (!OS::FileExists(dex_location_)) {
674 *error_msg = "Dex location " + std::string(dex_location_) + " does not exists.";
675 return false;
676 }
677
678 if (!Dex2Oat(args, error_msg)) {
679 // Manually delete the file. This ensures there is no garbage left over if
680 // the process unexpectedly died.
681 TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
682 return false;
683 }
684
685 // Mark that the oat file has changed and we should try to reload.
686 ClearOatFileCache();
687 return true;
688}
689
690bool OatFileAssistant::Dex2Oat(const std::vector<std::string>& args,
691 std::string* error_msg) {
692 Runtime* runtime = Runtime::Current();
693 std::string image_location = ImageLocation();
694 if (image_location.empty()) {
695 *error_msg = "No image location found for Dex2Oat.";
696 return false;
697 }
698
699 std::vector<std::string> argv;
700 argv.push_back(runtime->GetCompilerExecutable());
701 argv.push_back("--runtime-arg");
702 argv.push_back("-classpath");
703 argv.push_back("--runtime-arg");
704 argv.push_back(runtime->GetClassPathString());
705 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
706
707 if (!runtime->IsVerificationEnabled()) {
708 argv.push_back("--compiler-filter=verify-none");
709 }
710
711 if (runtime->MustRelocateIfPossible()) {
712 argv.push_back("--runtime-arg");
713 argv.push_back("-Xrelocate");
714 } else {
715 argv.push_back("--runtime-arg");
716 argv.push_back("-Xnorelocate");
717 }
718
719 if (!kIsTargetBuild) {
720 argv.push_back("--host");
721 }
722
723 argv.push_back("--boot-image=" + image_location);
724
725 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
726 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
727
728 argv.insert(argv.end(), args.begin(), args.end());
729
730 std::string command_line(Join(argv, ' '));
731 return Exec(argv, error_msg);
732}
733
734bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
735 InstructionSet isa, std::string* odex_filename, std::string* error_msg) {
736 CHECK(odex_filename != nullptr);
737 CHECK(error_msg != nullptr);
738
739 // The odex file name is formed by replacing the dex_location extension with
Richard Uhler63434112015-03-16 14:32:16 -0700740 // .odex and inserting an oat/<isa> directory. For example:
Richard Uhler66d874d2015-01-15 09:37:19 -0800741 // location = /foo/bar/baz.jar
Richard Uhler63434112015-03-16 14:32:16 -0700742 // odex_location = /foo/bar/oat/<isa>/baz.odex
Richard Uhler66d874d2015-01-15 09:37:19 -0800743
Richard Uhler63434112015-03-16 14:32:16 -0700744 // Find the directory portion of the dex location and add the oat/<isa>
745 // directory.
Richard Uhler66d874d2015-01-15 09:37:19 -0800746 size_t pos = location.rfind('/');
747 if (pos == std::string::npos) {
748 *error_msg = "Dex location " + location + " has no directory.";
749 return false;
750 }
751 std::string dir = location.substr(0, pos+1);
Richard Uhler63434112015-03-16 14:32:16 -0700752 dir += "oat/" + std::string(GetInstructionSetString(isa));
Richard Uhler66d874d2015-01-15 09:37:19 -0800753
754 // Find the file portion of the dex location.
755 std::string file;
756 if (pos == std::string::npos) {
757 file = location;
758 } else {
759 file = location.substr(pos+1);
760 }
761
762 // Get the base part of the file without the extension.
763 pos = file.rfind('.');
764 if (pos == std::string::npos) {
765 *error_msg = "Dex location " + location + " has no extension.";
766 return false;
767 }
768 std::string base = file.substr(0, pos);
769
770 *odex_filename = dir + "/" + base + ".odex";
771 return true;
772}
773
774std::string OatFileAssistant::DalvikCacheDirectory() {
775 // Note: We don't cache this, because it will only be called once by
776 // OatFileName, and we don't care about the performance of the profiling
777 // code, which isn't used in practice.
778
779 // TODO: The work done in GetDalvikCache is overkill for what we need.
780 // Ideally a new API for getting the DalvikCacheDirectory the way we want
781 // (without existence testing, creation, or death) is provided with the rest
782 // of the GetDalvikCache family of functions. Until such an API is in place,
783 // we use GetDalvikCache to avoid duplicating the logic for determining the
784 // dalvik cache directory.
785 std::string result;
786 bool have_android_data;
787 bool dalvik_cache_exists;
788 bool is_global_cache;
789 GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache);
790 return result;
791}
792
793std::string OatFileAssistant::ProfileFileName() {
794 if (package_name_ != nullptr) {
795 return DalvikCacheDirectory() + std::string("profiles/") + package_name_;
796 }
797 return "";
798}
799
800std::string OatFileAssistant::OldProfileFileName() {
801 std::string profile_name = ProfileFileName();
802 if (profile_name.empty()) {
803 return "";
804 }
805 return profile_name + "@old";
806}
807
808std::string OatFileAssistant::ImageLocation() {
809 Runtime* runtime = Runtime::Current();
810 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
811 if (image_space == nullptr) {
812 return "";
813 }
814 return image_space->GetImageLocation();
815}
816
817const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
818 if (!required_dex_checksum_attempted) {
819 required_dex_checksum_attempted = true;
820 required_dex_checksum_found = false;
821 std::string error_msg;
822 CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location";
823 if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum, &error_msg)) {
824 required_dex_checksum_found = true;
825 } else {
826 // This can happen if the original dex file has been stripped from the
827 // apk.
828 VLOG(oat) << "OatFileAssistant: " << error_msg;
829
830 // Get the checksum from the odex if we can.
831 const OatFile* odex_file = GetOdexFile();
832 if (odex_file != nullptr) {
833 const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
834 dex_location_, nullptr, false);
835 if (odex_dex_file != nullptr) {
836 cached_required_dex_checksum = odex_dex_file->GetDexFileLocationChecksum();
837 required_dex_checksum_found = true;
838 }
839 }
840 }
841 }
842 return required_dex_checksum_found ? &cached_required_dex_checksum : nullptr;
843}
844
845const OatFile* OatFileAssistant::GetOdexFile() {
846 CHECK(!oat_file_released_) << "OdexFile called after oat file released.";
847 if (!odex_file_load_attempted_) {
848 odex_file_load_attempted_ = true;
849 if (OdexFileName() != nullptr) {
850 const std::string& odex_file_name = *OdexFileName();
851 std::string error_msg;
852 cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
853 odex_file_name.c_str(), nullptr, nullptr, load_executable_,
Richard Uhlere5fed032015-03-18 08:21:11 -0700854 dex_location_, &error_msg));
Richard Uhler66d874d2015-01-15 09:37:19 -0800855 if (cached_odex_file_.get() == nullptr) {
856 VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
857 << odex_file_name << ": " << error_msg;
858 }
859 }
860 }
861 return cached_odex_file_.get();
862}
863
864void OatFileAssistant::ClearOdexFileCache() {
865 odex_file_load_attempted_ = false;
866 cached_odex_file_.reset();
867 odex_file_is_out_of_date_attempted_ = false;
868 odex_file_is_up_to_date_attempted_ = false;
869}
870
871const OatFile* OatFileAssistant::GetOatFile() {
872 CHECK(!oat_file_released_) << "OatFile called after oat file released.";
873 if (!oat_file_load_attempted_) {
874 oat_file_load_attempted_ = true;
875 if (OatFileName() != nullptr) {
876 const std::string& oat_file_name = *OatFileName();
877 std::string error_msg;
878 cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
Richard Uhlere5fed032015-03-18 08:21:11 -0700879 oat_file_name.c_str(), nullptr, nullptr, load_executable_,
880 dex_location_, &error_msg));
Richard Uhler66d874d2015-01-15 09:37:19 -0800881 if (cached_oat_file_.get() == nullptr) {
882 VLOG(oat) << "OatFileAssistant test for existing oat file "
883 << oat_file_name << ": " << error_msg;
884 }
885 }
886 }
887 return cached_oat_file_.get();
888}
889
890void OatFileAssistant::ClearOatFileCache() {
891 oat_file_load_attempted_ = false;
892 cached_oat_file_.reset();
893 oat_file_is_out_of_date_attempted_ = false;
894 oat_file_is_up_to_date_attempted_ = false;
895}
896
897const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
898 if (!image_info_load_attempted_) {
899 image_info_load_attempted_ = true;
900
901 Runtime* runtime = Runtime::Current();
902 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
903 if (image_space != nullptr) {
904 cached_image_info_.location = image_space->GetImageLocation();
905
906 if (isa_ == kRuntimeISA) {
907 const ImageHeader& image_header = image_space->GetImageHeader();
908 cached_image_info_.oat_checksum = image_header.GetOatChecksum();
909 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
910 cached_image_info_.patch_delta = image_header.GetPatchDelta();
911 } else {
912 std::unique_ptr<ImageHeader> image_header(
913 gc::space::ImageSpace::ReadImageHeaderOrDie(
914 cached_image_info_.location.c_str(), isa_));
915 cached_image_info_.oat_checksum = image_header->GetOatChecksum();
916 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin());
917 cached_image_info_.patch_delta = image_header->GetPatchDelta();
918 }
919 }
920 image_info_load_succeeded_ = (image_space != nullptr);
921 }
922 return image_info_load_succeeded_ ? &cached_image_info_ : nullptr;
923}
924
925ProfileFile* OatFileAssistant::GetProfile() {
926 if (!profile_load_attempted_) {
927 CHECK(package_name_ != nullptr)
928 << "pakage_name_ is nullptr: "
929 << "profile_load_attempted_ should have been true";
930 profile_load_attempted_ = true;
931 std::string profile_name = ProfileFileName();
932 if (!profile_name.empty()) {
933 profile_load_succeeded_ = cached_profile_.LoadFile(profile_name);
934 }
935 }
936 return profile_load_succeeded_ ? &cached_profile_ : nullptr;
937}
938
939ProfileFile* OatFileAssistant::GetOldProfile() {
940 if (!old_profile_load_attempted_) {
941 CHECK(package_name_ != nullptr)
942 << "pakage_name_ is nullptr: "
943 << "old_profile_load_attempted_ should have been true";
944 old_profile_load_attempted_ = true;
945 std::string old_profile_name = OldProfileFileName();
946 if (!old_profile_name.empty()) {
947 old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name);
948 }
949 }
950 return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr;
951}
952
953} // namespace art
954