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