blob: f87fa4f8f4676abda25523b1a50ebc43e6be32f2 [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
740 // .odex and inserting an isa directory. For example:
741 // location = /foo/bar/baz.jar
742 // odex_location = /foo/bar/<isa>/baz.odex
743
744 // Find the directory portion of the dex location and add the isa directory.
745 size_t pos = location.rfind('/');
746 if (pos == std::string::npos) {
747 *error_msg = "Dex location " + location + " has no directory.";
748 return false;
749 }
750 std::string dir = location.substr(0, pos+1);
751 dir += std::string(GetInstructionSetString(isa));
752
753 // Find the file portion of the dex location.
754 std::string file;
755 if (pos == std::string::npos) {
756 file = location;
757 } else {
758 file = location.substr(pos+1);
759 }
760
761 // Get the base part of the file without the extension.
762 pos = file.rfind('.');
763 if (pos == std::string::npos) {
764 *error_msg = "Dex location " + location + " has no extension.";
765 return false;
766 }
767 std::string base = file.substr(0, pos);
768
769 *odex_filename = dir + "/" + base + ".odex";
770 return true;
771}
772
773std::string OatFileAssistant::DalvikCacheDirectory() {
774 // Note: We don't cache this, because it will only be called once by
775 // OatFileName, and we don't care about the performance of the profiling
776 // code, which isn't used in practice.
777
778 // TODO: The work done in GetDalvikCache is overkill for what we need.
779 // Ideally a new API for getting the DalvikCacheDirectory the way we want
780 // (without existence testing, creation, or death) is provided with the rest
781 // of the GetDalvikCache family of functions. Until such an API is in place,
782 // we use GetDalvikCache to avoid duplicating the logic for determining the
783 // dalvik cache directory.
784 std::string result;
785 bool have_android_data;
786 bool dalvik_cache_exists;
787 bool is_global_cache;
788 GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache);
789 return result;
790}
791
792std::string OatFileAssistant::ProfileFileName() {
793 if (package_name_ != nullptr) {
794 return DalvikCacheDirectory() + std::string("profiles/") + package_name_;
795 }
796 return "";
797}
798
799std::string OatFileAssistant::OldProfileFileName() {
800 std::string profile_name = ProfileFileName();
801 if (profile_name.empty()) {
802 return "";
803 }
804 return profile_name + "@old";
805}
806
807std::string OatFileAssistant::ImageLocation() {
808 Runtime* runtime = Runtime::Current();
809 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
810 if (image_space == nullptr) {
811 return "";
812 }
813 return image_space->GetImageLocation();
814}
815
816const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
817 if (!required_dex_checksum_attempted) {
818 required_dex_checksum_attempted = true;
819 required_dex_checksum_found = false;
820 std::string error_msg;
821 CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location";
822 if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum, &error_msg)) {
823 required_dex_checksum_found = true;
824 } else {
825 // This can happen if the original dex file has been stripped from the
826 // apk.
827 VLOG(oat) << "OatFileAssistant: " << error_msg;
828
829 // Get the checksum from the odex if we can.
830 const OatFile* odex_file = GetOdexFile();
831 if (odex_file != nullptr) {
832 const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
833 dex_location_, nullptr, false);
834 if (odex_dex_file != nullptr) {
835 cached_required_dex_checksum = odex_dex_file->GetDexFileLocationChecksum();
836 required_dex_checksum_found = true;
837 }
838 }
839 }
840 }
841 return required_dex_checksum_found ? &cached_required_dex_checksum : nullptr;
842}
843
844const OatFile* OatFileAssistant::GetOdexFile() {
845 CHECK(!oat_file_released_) << "OdexFile called after oat file released.";
846 if (!odex_file_load_attempted_) {
847 odex_file_load_attempted_ = true;
848 if (OdexFileName() != nullptr) {
849 const std::string& odex_file_name = *OdexFileName();
850 std::string error_msg;
851 cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
852 odex_file_name.c_str(), nullptr, nullptr, load_executable_,
853 &error_msg));
854 if (cached_odex_file_.get() == nullptr) {
855 VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
856 << odex_file_name << ": " << error_msg;
857 }
858 }
859 }
860 return cached_odex_file_.get();
861}
862
863void OatFileAssistant::ClearOdexFileCache() {
864 odex_file_load_attempted_ = false;
865 cached_odex_file_.reset();
866 odex_file_is_out_of_date_attempted_ = false;
867 odex_file_is_up_to_date_attempted_ = false;
868}
869
870const OatFile* OatFileAssistant::GetOatFile() {
871 CHECK(!oat_file_released_) << "OatFile called after oat file released.";
872 if (!oat_file_load_attempted_) {
873 oat_file_load_attempted_ = true;
874 if (OatFileName() != nullptr) {
875 const std::string& oat_file_name = *OatFileName();
876 std::string error_msg;
877 cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
878 oat_file_name.c_str(), nullptr, nullptr, load_executable_, &error_msg));
879 if (cached_oat_file_.get() == nullptr) {
880 VLOG(oat) << "OatFileAssistant test for existing oat file "
881 << oat_file_name << ": " << error_msg;
882 }
883 }
884 }
885 return cached_oat_file_.get();
886}
887
888void OatFileAssistant::ClearOatFileCache() {
889 oat_file_load_attempted_ = false;
890 cached_oat_file_.reset();
891 oat_file_is_out_of_date_attempted_ = false;
892 oat_file_is_up_to_date_attempted_ = false;
893}
894
895const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
896 if (!image_info_load_attempted_) {
897 image_info_load_attempted_ = true;
898
899 Runtime* runtime = Runtime::Current();
900 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
901 if (image_space != nullptr) {
902 cached_image_info_.location = image_space->GetImageLocation();
903
904 if (isa_ == kRuntimeISA) {
905 const ImageHeader& image_header = image_space->GetImageHeader();
906 cached_image_info_.oat_checksum = image_header.GetOatChecksum();
907 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
908 cached_image_info_.patch_delta = image_header.GetPatchDelta();
909 } else {
910 std::unique_ptr<ImageHeader> image_header(
911 gc::space::ImageSpace::ReadImageHeaderOrDie(
912 cached_image_info_.location.c_str(), isa_));
913 cached_image_info_.oat_checksum = image_header->GetOatChecksum();
914 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin());
915 cached_image_info_.patch_delta = image_header->GetPatchDelta();
916 }
917 }
918 image_info_load_succeeded_ = (image_space != nullptr);
919 }
920 return image_info_load_succeeded_ ? &cached_image_info_ : nullptr;
921}
922
923ProfileFile* OatFileAssistant::GetProfile() {
924 if (!profile_load_attempted_) {
925 CHECK(package_name_ != nullptr)
926 << "pakage_name_ is nullptr: "
927 << "profile_load_attempted_ should have been true";
928 profile_load_attempted_ = true;
929 std::string profile_name = ProfileFileName();
930 if (!profile_name.empty()) {
931 profile_load_succeeded_ = cached_profile_.LoadFile(profile_name);
932 }
933 }
934 return profile_load_succeeded_ ? &cached_profile_ : nullptr;
935}
936
937ProfileFile* OatFileAssistant::GetOldProfile() {
938 if (!old_profile_load_attempted_) {
939 CHECK(package_name_ != nullptr)
940 << "pakage_name_ is nullptr: "
941 << "old_profile_load_attempted_ should have been true";
942 old_profile_load_attempted_ = true;
943 std::string old_profile_name = OldProfileFileName();
944 if (!old_profile_name.empty()) {
945 old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name);
946 }
947 }
948 return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr;
949}
950
951} // namespace art
952