blob: d0bfe6eb56c277937d2a436278e7c6df16e26a9f [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.
Richard Uhler581f4e92015-05-07 10:19:35 -070099 if (flock_.HasFile()) {
100 TEMP_FAILURE_RETRY(unlink(flock_.GetFile()->GetPath().c_str()));
Richard Uhler66d874d2015-01-15 09:37:19 -0800101 }
102}
103
104bool 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
121bool OatFileAssistant::Lock(std::string* error_msg) {
122 CHECK(error_msg != nullptr);
Richard Uhler581f4e92015-05-07 10:19:35 -0700123 CHECK(!flock_.HasFile()) << "OatFileAssistant::Lock already acquired";
Richard Uhler66d874d2015-01-15 09:37:19 -0800124
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
Richard Uhler581f4e92015-05-07 10:19:35 -0700131 if (!flock_.Init(lock_file_name.c_str(), error_msg)) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800132 TEMP_FAILURE_RETRY(unlink(lock_file_name.c_str()));
133 return false;
134 }
135 return true;
136}
137
Richard Uhler95abd042015-03-24 09:51:28 -0700138OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() {
Richard Uhler66d874d2015-01-15 09:37:19 -0800139 // 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
Richard Uhler95abd042015-03-24 09:51:28 -0700142 if (OatFileIsUpToDate() || OdexFileIsUpToDate()) {
143 return kNoDexOptNeeded;
Richard Uhler66d874d2015-01-15 09:37:19 -0800144 }
Richard Uhler95abd042015-03-24 09:51:28 -0700145
146 if (OdexFileNeedsRelocation()) {
147 return kPatchOatNeeded;
148 }
149
150 if (OatFileNeedsRelocation()) {
151 return kSelfPatchOatNeeded;
152 }
153
154 return kDex2OatNeeded;
Richard Uhler66d874d2015-01-15 09:37:19 -0800155}
156
157bool OatFileAssistant::MakeUpToDate(std::string* error_msg) {
Richard Uhler95abd042015-03-24 09:51:28 -0700158 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);
Richard Uhler66d874d2015-01-15 09:37:19 -0800163 }
164 UNREACHABLE();
165}
166
167std::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
204std::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
Andreas Gampe90e34042015-04-27 20:01:52 -0700226 for (size_t i = 1; ; i++) {
227 std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location);
Richard Uhler66d874d2015-01-15 09:37:19 -0800228 oat_dex_file = oat_file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700229 if (oat_dex_file == nullptr) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800230 // 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
244const std::string* OatFileAssistant::OdexFileName() {
245 if (!cached_odex_file_name_attempted_) {
246 CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
247 cached_odex_file_name_attempted_ = true;
248
249 std::string error_msg;
250 cached_odex_file_name_found_ = DexFilenameToOdexFilename(
251 dex_location_, isa_, &cached_odex_file_name_, &error_msg);
252 if (!cached_odex_file_name_found_) {
253 // If we can't figure out the odex file, we treat it as if the odex
254 // file was inaccessible.
255 LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
256 }
257 }
258 return cached_odex_file_name_found_ ? &cached_odex_file_name_ : nullptr;
259}
260
261bool OatFileAssistant::OdexFileExists() {
262 return GetOdexFile() != nullptr;
263}
264
Richard Uhler95abd042015-03-24 09:51:28 -0700265OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() {
Richard Uhler66d874d2015-01-15 09:37:19 -0800266 if (OdexFileIsOutOfDate()) {
Richard Uhler95abd042015-03-24 09:51:28 -0700267 return kOatOutOfDate;
Richard Uhler66d874d2015-01-15 09:37:19 -0800268 }
269 if (OdexFileIsUpToDate()) {
Richard Uhler95abd042015-03-24 09:51:28 -0700270 return kOatUpToDate;
Richard Uhler66d874d2015-01-15 09:37:19 -0800271 }
Richard Uhler95abd042015-03-24 09:51:28 -0700272 return kOatNeedsRelocation;
Richard Uhler66d874d2015-01-15 09:37:19 -0800273}
274
275bool OatFileAssistant::OdexFileIsOutOfDate() {
276 if (!odex_file_is_out_of_date_attempted_) {
277 odex_file_is_out_of_date_attempted_ = true;
278 const OatFile* odex_file = GetOdexFile();
279 if (odex_file == nullptr) {
280 cached_odex_file_is_out_of_date_ = true;
281 } else {
282 cached_odex_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*odex_file);
283 }
284 }
285 return cached_odex_file_is_out_of_date_;
286}
287
288bool OatFileAssistant::OdexFileNeedsRelocation() {
Richard Uhler95abd042015-03-24 09:51:28 -0700289 return OdexFileStatus() == kOatNeedsRelocation;
Richard Uhler66d874d2015-01-15 09:37:19 -0800290}
291
292bool OatFileAssistant::OdexFileIsUpToDate() {
293 if (!odex_file_is_up_to_date_attempted_) {
294 odex_file_is_up_to_date_attempted_ = true;
295 const OatFile* odex_file = GetOdexFile();
296 if (odex_file == nullptr) {
297 cached_odex_file_is_up_to_date_ = false;
298 } else {
299 cached_odex_file_is_up_to_date_ = GivenOatFileIsUpToDate(*odex_file);
300 }
301 }
302 return cached_odex_file_is_up_to_date_;
303}
304
305const std::string* OatFileAssistant::OatFileName() {
306 if (!cached_oat_file_name_attempted_) {
307 cached_oat_file_name_attempted_ = true;
308
309 // Compute the oat file name from the dex location.
310 CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location";
311
312 // TODO: The oat file assistant should be the definitive place for
313 // determining the oat file name from the dex location, not
314 // GetDalvikCacheFilename.
315 std::string cache_dir = StringPrintf("%s%s",
316 DalvikCacheDirectory().c_str(), GetInstructionSetString(isa_));
317 std::string error_msg;
318 cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_,
319 cache_dir.c_str(), &cached_oat_file_name_, &error_msg);
320 if (!cached_oat_file_name_found_) {
321 // If we can't determine the oat file name, we treat the oat file as
322 // inaccessible.
323 LOG(WARNING) << "Failed to determine oat file name for dex location "
324 << dex_location_ << ": " << error_msg;
325 }
326 }
327 return cached_oat_file_name_found_ ? &cached_oat_file_name_ : nullptr;
328}
329
330bool OatFileAssistant::OatFileExists() {
331 return GetOatFile() != nullptr;
332}
333
Richard Uhler95abd042015-03-24 09:51:28 -0700334OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() {
Richard Uhler66d874d2015-01-15 09:37:19 -0800335 if (OatFileIsOutOfDate()) {
Richard Uhler95abd042015-03-24 09:51:28 -0700336 return kOatOutOfDate;
Richard Uhler66d874d2015-01-15 09:37:19 -0800337 }
338 if (OatFileIsUpToDate()) {
Richard Uhler95abd042015-03-24 09:51:28 -0700339 return kOatUpToDate;
Richard Uhler66d874d2015-01-15 09:37:19 -0800340 }
Richard Uhler95abd042015-03-24 09:51:28 -0700341 return kOatNeedsRelocation;
Richard Uhler66d874d2015-01-15 09:37:19 -0800342}
343
344bool OatFileAssistant::OatFileIsOutOfDate() {
345 if (!oat_file_is_out_of_date_attempted_) {
346 oat_file_is_out_of_date_attempted_ = true;
347 const OatFile* oat_file = GetOatFile();
348 if (oat_file == nullptr) {
349 cached_oat_file_is_out_of_date_ = true;
350 } else {
351 cached_oat_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*oat_file);
352 }
353 }
354 return cached_oat_file_is_out_of_date_;
355}
356
357bool OatFileAssistant::OatFileNeedsRelocation() {
Richard Uhler95abd042015-03-24 09:51:28 -0700358 return OatFileStatus() == kOatNeedsRelocation;
Richard Uhler66d874d2015-01-15 09:37:19 -0800359}
360
361bool OatFileAssistant::OatFileIsUpToDate() {
362 if (!oat_file_is_up_to_date_attempted_) {
363 oat_file_is_up_to_date_attempted_ = true;
364 const OatFile* oat_file = GetOatFile();
365 if (oat_file == nullptr) {
366 cached_oat_file_is_up_to_date_ = false;
367 } else {
368 cached_oat_file_is_up_to_date_ = GivenOatFileIsUpToDate(*oat_file);
369 }
370 }
371 return cached_oat_file_is_up_to_date_;
372}
373
Richard Uhler95abd042015-03-24 09:51:28 -0700374OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800375 // TODO: This could cause GivenOatFileIsOutOfDate to be called twice, which
376 // is more work than we need to do. If performance becomes a concern, and
377 // this method is actually called, this should be fixed.
378 if (GivenOatFileIsOutOfDate(file)) {
Richard Uhler95abd042015-03-24 09:51:28 -0700379 return kOatOutOfDate;
Richard Uhler66d874d2015-01-15 09:37:19 -0800380 }
381 if (GivenOatFileIsUpToDate(file)) {
Richard Uhler95abd042015-03-24 09:51:28 -0700382 return kOatUpToDate;
Richard Uhler66d874d2015-01-15 09:37:19 -0800383 }
Richard Uhler95abd042015-03-24 09:51:28 -0700384 return kOatNeedsRelocation;
Richard Uhler66d874d2015-01-15 09:37:19 -0800385}
386
387bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
388 // Verify the dex checksum.
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700389 // Note: GetOatDexFile will return null if the dex checksum doesn't match
Richard Uhler66d874d2015-01-15 09:37:19 -0800390 // what we provide, which verifies the primary dex checksum for us.
391 const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum();
392 const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(
393 dex_location_, dex_checksum_pointer, false);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700394 if (oat_dex_file == nullptr) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800395 return true;
396 }
397
398 // Verify the dex checksums for any secondary multidex files
Andreas Gampe90e34042015-04-27 20:01:52 -0700399 for (size_t i = 1; ; i++) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800400 std::string secondary_dex_location
Andreas Gampe90e34042015-04-27 20:01:52 -0700401 = DexFile::GetMultiDexLocation(i, dex_location_);
Richard Uhler66d874d2015-01-15 09:37:19 -0800402 const OatFile::OatDexFile* secondary_oat_dex_file
403 = file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700404 if (secondary_oat_dex_file == nullptr) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800405 // There are no more secondary dex files to check.
406 break;
407 }
408
409 std::string error_msg;
410 uint32_t expected_secondary_checksum = 0;
411 if (DexFile::GetChecksum(secondary_dex_location.c_str(),
412 &expected_secondary_checksum, &error_msg)) {
413 uint32_t actual_secondary_checksum
414 = secondary_oat_dex_file->GetDexFileLocationChecksum();
415 if (expected_secondary_checksum != actual_secondary_checksum) {
416 VLOG(oat) << "Dex checksum does not match for secondary dex: "
417 << secondary_dex_location
418 << ". Expected: " << expected_secondary_checksum
419 << ", Actual: " << actual_secondary_checksum;
420 return false;
421 }
422 } else {
423 // If we can't get the checksum for the secondary location, we assume
424 // the dex checksum is up to date for this and all other secondary dex
425 // files.
426 break;
427 }
428 }
429
430 // Verify the image checksum
431 const ImageInfo* image_info = GetImageInfo();
432 if (image_info == nullptr) {
433 VLOG(oat) << "No image for oat image checksum to match against.";
434 return true;
435 }
436
437 if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) {
438 VLOG(oat) << "Oat image checksum does not match image checksum.";
439 return true;
440 }
441
442 // The checksums are all good; the dex file is not out of date.
443 return false;
444}
445
446bool OatFileAssistant::GivenOatFileNeedsRelocation(const OatFile& file) {
Richard Uhler95abd042015-03-24 09:51:28 -0700447 return GivenOatFileStatus(file) == kOatNeedsRelocation;
Richard Uhler66d874d2015-01-15 09:37:19 -0800448}
449
450bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
451 if (GivenOatFileIsOutOfDate(file)) {
452 return false;
453 }
454
455 if (file.IsPic()) {
456 return true;
457 }
458
459 const ImageInfo* image_info = GetImageInfo();
460 if (image_info == nullptr) {
Richard Uhlerf7f798c2015-05-11 09:36:57 -0700461 VLOG(oat) << "No image to check oat relocation against.";
Richard Uhler66d874d2015-01-15 09:37:19 -0800462 return false;
463 }
464
465 // Verify the oat_data_begin recorded for the image in the oat file matches
466 // the actual oat_data_begin for boot.oat in the image.
467 const OatHeader& oat_header = file.GetOatHeader();
468 uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
469 if (oat_data_begin != image_info->oat_data_begin) {
470 VLOG(oat) << file.GetLocation() <<
471 ": Oat file image oat_data_begin (" << oat_data_begin << ")"
472 << " does not match actual image oat_data_begin ("
473 << image_info->oat_data_begin << ")";
474 return false;
475 }
476
477 // Verify the oat_patch_delta recorded for the image in the oat file matches
478 // the actual oat_patch_delta for the image.
479 int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
480 if (oat_patch_delta != image_info->patch_delta) {
481 VLOG(oat) << file.GetLocation() <<
482 ": Oat file image patch delta (" << oat_patch_delta << ")"
483 << " does not match actual image patch delta ("
484 << image_info->patch_delta << ")";
485 return false;
486 }
487 return true;
488}
489
490bool OatFileAssistant::ProfileExists() {
491 return GetProfile() != nullptr;
492}
493
494bool OatFileAssistant::OldProfileExists() {
495 return GetOldProfile() != nullptr;
496}
497
498// TODO: The IsProfileChangeSignificant implementation was copied from likely
499// bit-rotted code.
500bool OatFileAssistant::IsProfileChangeSignificant() {
501 ProfileFile* profile = GetProfile();
502 if (profile == nullptr) {
503 return false;
504 }
505
506 ProfileFile* old_profile = GetOldProfile();
507 if (old_profile == nullptr) {
508 return false;
509 }
510
511 // TODO: The following code to compare two profile files should live with
512 // the rest of the profiler code, not the oat file assistant code.
513
514 // A change in profile is considered significant if X% (change_thr property)
515 // of the top K% (compile_thr property) samples has changed.
516 const ProfilerOptions& options = Runtime::Current()->GetProfilerOptions();
517 const double top_k_threshold = options.GetTopKThreshold();
518 const double change_threshold = options.GetTopKChangeThreshold();
519 std::set<std::string> top_k, old_top_k;
520 profile->GetTopKSamples(top_k, top_k_threshold);
521 old_profile->GetTopKSamples(old_top_k, top_k_threshold);
522 std::set<std::string> diff;
523 std::set_difference(top_k.begin(), top_k.end(), old_top_k.begin(),
524 old_top_k.end(), std::inserter(diff, diff.end()));
525
526 // TODO: consider using the usedPercentage instead of the plain diff count.
527 double change_percent = 100.0 * static_cast<double>(diff.size())
528 / static_cast<double>(top_k.size());
529 std::set<std::string>::iterator end = diff.end();
530 for (std::set<std::string>::iterator it = diff.begin(); it != end; it++) {
531 VLOG(oat) << "Profile new in topK: " << *it;
532 }
533
534 if (change_percent > change_threshold) {
535 VLOG(oat) << "Oat File Assistant: Profile for " << dex_location_
536 << "has changed significantly: (top "
537 << top_k_threshold << "% samples changed in proportion of "
538 << change_percent << "%)";
539 return true;
540 }
541 return false;
542}
543
544// TODO: The CopyProfileFile implementation was copied from likely bit-rotted
545// code.
546void OatFileAssistant::CopyProfileFile() {
547 if (!ProfileExists()) {
548 return;
549 }
550
551 std::string profile_name = ProfileFileName();
552 std::string old_profile_name = OldProfileFileName();
553
554 ScopedFd src(open(old_profile_name.c_str(), O_RDONLY));
555 if (src.get() == -1) {
556 PLOG(WARNING) << "Failed to open profile file " << old_profile_name
557 << ". My uid:gid is " << getuid() << ":" << getgid();
558 return;
559 }
560
561 struct stat stat_src;
562 if (fstat(src.get(), &stat_src) == -1) {
563 PLOG(WARNING) << "Failed to get stats for profile file " << old_profile_name
564 << ". My uid:gid is " << getuid() << ":" << getgid();
565 return;
566 }
567
568 // Create the copy with rw------- (only accessible by system)
569 ScopedFd dst(open(profile_name.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0600));
570 if (dst.get() == -1) {
571 PLOG(WARNING) << "Failed to create/write prev profile file " << profile_name
572 << ". My uid:gid is " << getuid() << ":" << getgid();
573 return;
574 }
575
576#ifdef __linux__
577 if (sendfile(dst.get(), src.get(), nullptr, stat_src.st_size) == -1) {
578#else
579 off_t len;
580 if (sendfile(dst.get(), src.get(), 0, &len, nullptr, 0) == -1) {
581#endif
582 PLOG(WARNING) << "Failed to copy profile file " << old_profile_name
583 << " to " << profile_name << ". My uid:gid is " << getuid()
584 << ":" << getgid();
585 }
586}
587
Richard Uhler95abd042015-03-24 09:51:28 -0700588bool OatFileAssistant::RelocateOatFile(const std::string* input_file,
589 std::string* error_msg) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800590 CHECK(error_msg != nullptr);
591
Richard Uhler95abd042015-03-24 09:51:28 -0700592 if (input_file == nullptr) {
Richard Uhler66d874d2015-01-15 09:37:19 -0800593 *error_msg = "Patching of oat file for dex location "
594 + std::string(dex_location_)
Richard Uhler95abd042015-03-24 09:51:28 -0700595 + " not attempted because the input file name could not be determined.";
Richard Uhler66d874d2015-01-15 09:37:19 -0800596 return false;
597 }
Richard Uhler95abd042015-03-24 09:51:28 -0700598 const std::string& input_file_name = *input_file;
Richard Uhler66d874d2015-01-15 09:37:19 -0800599
600 if (OatFileName() == nullptr) {
601 *error_msg = "Patching of oat file for dex location "
602 + std::string(dex_location_)
603 + " not attempted because the oat file name could not be determined.";
604 return false;
605 }
606 const std::string& oat_file_name = *OatFileName();
607
608 const ImageInfo* image_info = GetImageInfo();
609 Runtime* runtime = Runtime::Current();
610 if (image_info == nullptr) {
611 *error_msg = "Patching of oat file " + oat_file_name
612 + " not attempted because no image location was found.";
613 return false;
614 }
615
616 if (!runtime->IsDex2OatEnabled()) {
617 *error_msg = "Patching of oat file " + oat_file_name
618 + " not attempted because dex2oat is disabled";
619 return false;
620 }
621
622 std::vector<std::string> argv;
623 argv.push_back(runtime->GetPatchoatExecutable());
624 argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(isa_)));
Richard Uhler95abd042015-03-24 09:51:28 -0700625 argv.push_back("--input-oat-file=" + input_file_name);
Richard Uhler66d874d2015-01-15 09:37:19 -0800626 argv.push_back("--output-oat-file=" + oat_file_name);
627 argv.push_back("--patched-image-location=" + image_info->location);
628
629 std::string command_line(Join(argv, ' '));
630 if (!Exec(argv, error_msg)) {
631 // Manually delete the file. This ensures there is no garbage left over if
632 // the process unexpectedly died.
633 TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
634 return false;
635 }
636
637 // Mark that the oat file has changed and we should try to reload.
638 ClearOatFileCache();
639 return true;
640}
641
642bool OatFileAssistant::GenerateOatFile(std::string* error_msg) {
643 CHECK(error_msg != nullptr);
644
645 if (OatFileName() == nullptr) {
646 *error_msg = "Generation of oat file for dex location "
647 + std::string(dex_location_)
648 + " not attempted because the oat file name could not be determined.";
649 return false;
650 }
651 const std::string& oat_file_name = *OatFileName();
652
653 Runtime* runtime = Runtime::Current();
654 if (!runtime->IsDex2OatEnabled()) {
655 *error_msg = "Generation of oat file " + oat_file_name
656 + " not attempted because dex2oat is disabled";
657 return false;
658 }
659
660 std::vector<std::string> args;
661 args.push_back("--dex-file=" + std::string(dex_location_));
662 args.push_back("--oat-file=" + oat_file_name);
663
664 // dex2oat ignores missing dex files and doesn't report an error.
665 // Check explicitly here so we can detect the error properly.
666 // TODO: Why does dex2oat behave that way?
667 if (!OS::FileExists(dex_location_)) {
668 *error_msg = "Dex location " + std::string(dex_location_) + " does not exists.";
669 return false;
670 }
671
672 if (!Dex2Oat(args, error_msg)) {
673 // Manually delete the file. This ensures there is no garbage left over if
674 // the process unexpectedly died.
675 TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str()));
676 return false;
677 }
678
679 // Mark that the oat file has changed and we should try to reload.
680 ClearOatFileCache();
681 return true;
682}
683
684bool OatFileAssistant::Dex2Oat(const std::vector<std::string>& args,
685 std::string* error_msg) {
686 Runtime* runtime = Runtime::Current();
687 std::string image_location = ImageLocation();
688 if (image_location.empty()) {
689 *error_msg = "No image location found for Dex2Oat.";
690 return false;
691 }
692
Sebastien Hertz0de11332015-05-13 12:14:05 +0200693 ClassLinker* linker = runtime->GetClassLinker();
694 CHECK(linker != nullptr) << "ClassLinker is not created yet";
695 const OatFile* primary_oat_file = linker->GetPrimaryOatFile();
696 const bool debuggable = primary_oat_file != nullptr && primary_oat_file->IsDebuggable();
697
Richard Uhler66d874d2015-01-15 09:37:19 -0800698 std::vector<std::string> argv;
699 argv.push_back(runtime->GetCompilerExecutable());
700 argv.push_back("--runtime-arg");
701 argv.push_back("-classpath");
702 argv.push_back("--runtime-arg");
703 argv.push_back(runtime->GetClassPathString());
Sebastien Hertz0de11332015-05-13 12:14:05 +0200704 if (debuggable) {
705 argv.push_back("--debuggable");
706 }
Richard Uhler66d874d2015-01-15 09:37:19 -0800707 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
708
709 if (!runtime->IsVerificationEnabled()) {
710 argv.push_back("--compiler-filter=verify-none");
711 }
712
713 if (runtime->MustRelocateIfPossible()) {
714 argv.push_back("--runtime-arg");
715 argv.push_back("-Xrelocate");
716 } else {
717 argv.push_back("--runtime-arg");
718 argv.push_back("-Xnorelocate");
719 }
720
721 if (!kIsTargetBuild) {
722 argv.push_back("--host");
723 }
724
725 argv.push_back("--boot-image=" + image_location);
726
727 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
728 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
729
730 argv.insert(argv.end(), args.begin(), args.end());
731
732 std::string command_line(Join(argv, ' '));
733 return Exec(argv, error_msg);
734}
735
736bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
737 InstructionSet isa, std::string* odex_filename, std::string* error_msg) {
738 CHECK(odex_filename != nullptr);
739 CHECK(error_msg != nullptr);
740
741 // The odex file name is formed by replacing the dex_location extension with
Richard Uhler63434112015-03-16 14:32:16 -0700742 // .odex and inserting an oat/<isa> directory. For example:
Richard Uhler66d874d2015-01-15 09:37:19 -0800743 // location = /foo/bar/baz.jar
Richard Uhler63434112015-03-16 14:32:16 -0700744 // odex_location = /foo/bar/oat/<isa>/baz.odex
Richard Uhler66d874d2015-01-15 09:37:19 -0800745
Richard Uhler63434112015-03-16 14:32:16 -0700746 // Find the directory portion of the dex location and add the oat/<isa>
747 // directory.
Richard Uhler66d874d2015-01-15 09:37:19 -0800748 size_t pos = location.rfind('/');
749 if (pos == std::string::npos) {
750 *error_msg = "Dex location " + location + " has no directory.";
751 return false;
752 }
753 std::string dir = location.substr(0, pos+1);
Richard Uhler63434112015-03-16 14:32:16 -0700754 dir += "oat/" + std::string(GetInstructionSetString(isa));
Richard Uhler66d874d2015-01-15 09:37:19 -0800755
756 // Find the file portion of the dex location.
757 std::string file;
758 if (pos == std::string::npos) {
759 file = location;
760 } else {
761 file = location.substr(pos+1);
762 }
763
764 // Get the base part of the file without the extension.
765 pos = file.rfind('.');
766 if (pos == std::string::npos) {
767 *error_msg = "Dex location " + location + " has no extension.";
768 return false;
769 }
770 std::string base = file.substr(0, pos);
771
772 *odex_filename = dir + "/" + base + ".odex";
773 return true;
774}
775
776std::string OatFileAssistant::DalvikCacheDirectory() {
777 // Note: We don't cache this, because it will only be called once by
778 // OatFileName, and we don't care about the performance of the profiling
779 // code, which isn't used in practice.
780
781 // TODO: The work done in GetDalvikCache is overkill for what we need.
782 // Ideally a new API for getting the DalvikCacheDirectory the way we want
783 // (without existence testing, creation, or death) is provided with the rest
784 // of the GetDalvikCache family of functions. Until such an API is in place,
785 // we use GetDalvikCache to avoid duplicating the logic for determining the
786 // dalvik cache directory.
787 std::string result;
788 bool have_android_data;
789 bool dalvik_cache_exists;
790 bool is_global_cache;
791 GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache);
792 return result;
793}
794
795std::string OatFileAssistant::ProfileFileName() {
796 if (package_name_ != nullptr) {
797 return DalvikCacheDirectory() + std::string("profiles/") + package_name_;
798 }
799 return "";
800}
801
802std::string OatFileAssistant::OldProfileFileName() {
803 std::string profile_name = ProfileFileName();
804 if (profile_name.empty()) {
805 return "";
806 }
807 return profile_name + "@old";
808}
809
810std::string OatFileAssistant::ImageLocation() {
811 Runtime* runtime = Runtime::Current();
812 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
813 if (image_space == nullptr) {
814 return "";
815 }
816 return image_space->GetImageLocation();
817}
818
819const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
820 if (!required_dex_checksum_attempted) {
821 required_dex_checksum_attempted = true;
822 required_dex_checksum_found = false;
823 std::string error_msg;
824 CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location";
825 if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum, &error_msg)) {
826 required_dex_checksum_found = true;
827 } else {
828 // This can happen if the original dex file has been stripped from the
829 // apk.
830 VLOG(oat) << "OatFileAssistant: " << error_msg;
831
832 // Get the checksum from the odex if we can.
833 const OatFile* odex_file = GetOdexFile();
834 if (odex_file != nullptr) {
835 const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
836 dex_location_, nullptr, false);
837 if (odex_dex_file != nullptr) {
838 cached_required_dex_checksum = odex_dex_file->GetDexFileLocationChecksum();
839 required_dex_checksum_found = true;
840 }
841 }
842 }
843 }
844 return required_dex_checksum_found ? &cached_required_dex_checksum : nullptr;
845}
846
847const OatFile* OatFileAssistant::GetOdexFile() {
848 CHECK(!oat_file_released_) << "OdexFile called after oat file released.";
849 if (!odex_file_load_attempted_) {
850 odex_file_load_attempted_ = true;
851 if (OdexFileName() != nullptr) {
852 const std::string& odex_file_name = *OdexFileName();
853 std::string error_msg;
854 cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
855 odex_file_name.c_str(), nullptr, nullptr, load_executable_,
Richard Uhlere5fed032015-03-18 08:21:11 -0700856 dex_location_, &error_msg));
Richard Uhler66d874d2015-01-15 09:37:19 -0800857 if (cached_odex_file_.get() == nullptr) {
858 VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
859 << odex_file_name << ": " << error_msg;
860 }
861 }
862 }
863 return cached_odex_file_.get();
864}
865
866void OatFileAssistant::ClearOdexFileCache() {
867 odex_file_load_attempted_ = false;
868 cached_odex_file_.reset();
869 odex_file_is_out_of_date_attempted_ = false;
870 odex_file_is_up_to_date_attempted_ = false;
871}
872
873const OatFile* OatFileAssistant::GetOatFile() {
874 CHECK(!oat_file_released_) << "OatFile called after oat file released.";
875 if (!oat_file_load_attempted_) {
876 oat_file_load_attempted_ = true;
877 if (OatFileName() != nullptr) {
878 const std::string& oat_file_name = *OatFileName();
879 std::string error_msg;
880 cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
Richard Uhlere5fed032015-03-18 08:21:11 -0700881 oat_file_name.c_str(), nullptr, nullptr, load_executable_,
882 dex_location_, &error_msg));
Richard Uhler66d874d2015-01-15 09:37:19 -0800883 if (cached_oat_file_.get() == nullptr) {
884 VLOG(oat) << "OatFileAssistant test for existing oat file "
885 << oat_file_name << ": " << error_msg;
886 }
887 }
888 }
889 return cached_oat_file_.get();
890}
891
892void OatFileAssistant::ClearOatFileCache() {
893 oat_file_load_attempted_ = false;
894 cached_oat_file_.reset();
895 oat_file_is_out_of_date_attempted_ = false;
896 oat_file_is_up_to_date_attempted_ = false;
897}
898
899const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
900 if (!image_info_load_attempted_) {
901 image_info_load_attempted_ = true;
902
903 Runtime* runtime = Runtime::Current();
904 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
905 if (image_space != nullptr) {
906 cached_image_info_.location = image_space->GetImageLocation();
907
908 if (isa_ == kRuntimeISA) {
909 const ImageHeader& image_header = image_space->GetImageHeader();
910 cached_image_info_.oat_checksum = image_header.GetOatChecksum();
911 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
912 cached_image_info_.patch_delta = image_header.GetPatchDelta();
913 } else {
914 std::unique_ptr<ImageHeader> image_header(
915 gc::space::ImageSpace::ReadImageHeaderOrDie(
916 cached_image_info_.location.c_str(), isa_));
917 cached_image_info_.oat_checksum = image_header->GetOatChecksum();
918 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin());
919 cached_image_info_.patch_delta = image_header->GetPatchDelta();
920 }
921 }
922 image_info_load_succeeded_ = (image_space != nullptr);
923 }
924 return image_info_load_succeeded_ ? &cached_image_info_ : nullptr;
925}
926
927ProfileFile* OatFileAssistant::GetProfile() {
928 if (!profile_load_attempted_) {
929 CHECK(package_name_ != nullptr)
930 << "pakage_name_ is nullptr: "
931 << "profile_load_attempted_ should have been true";
932 profile_load_attempted_ = true;
933 std::string profile_name = ProfileFileName();
934 if (!profile_name.empty()) {
935 profile_load_succeeded_ = cached_profile_.LoadFile(profile_name);
936 }
937 }
938 return profile_load_succeeded_ ? &cached_profile_ : nullptr;
939}
940
941ProfileFile* OatFileAssistant::GetOldProfile() {
942 if (!old_profile_load_attempted_) {
943 CHECK(package_name_ != nullptr)
944 << "pakage_name_ is nullptr: "
945 << "old_profile_load_attempted_ should have been true";
946 old_profile_load_attempted_ = true;
947 std::string old_profile_name = OldProfileFileName();
948 if (!old_profile_name.empty()) {
949 old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name);
950 }
951 }
952 return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr;
953}
954
955} // namespace art
956