blob: d07c09cd9a45cadee16b2b3e1f087ae72cd3eade [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
693 std::vector<std::string> argv;
694 argv.push_back(runtime->GetCompilerExecutable());
695 argv.push_back("--runtime-arg");
696 argv.push_back("-classpath");
697 argv.push_back("--runtime-arg");
698 argv.push_back(runtime->GetClassPathString());
699 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
700
701 if (!runtime->IsVerificationEnabled()) {
702 argv.push_back("--compiler-filter=verify-none");
703 }
704
705 if (runtime->MustRelocateIfPossible()) {
706 argv.push_back("--runtime-arg");
707 argv.push_back("-Xrelocate");
708 } else {
709 argv.push_back("--runtime-arg");
710 argv.push_back("-Xnorelocate");
711 }
712
713 if (!kIsTargetBuild) {
714 argv.push_back("--host");
715 }
716
717 argv.push_back("--boot-image=" + image_location);
718
719 std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
720 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
721
722 argv.insert(argv.end(), args.begin(), args.end());
723
724 std::string command_line(Join(argv, ' '));
725 return Exec(argv, error_msg);
726}
727
728bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
729 InstructionSet isa, std::string* odex_filename, std::string* error_msg) {
730 CHECK(odex_filename != nullptr);
731 CHECK(error_msg != nullptr);
732
733 // The odex file name is formed by replacing the dex_location extension with
Richard Uhler63434112015-03-16 14:32:16 -0700734 // .odex and inserting an oat/<isa> directory. For example:
Richard Uhler66d874d2015-01-15 09:37:19 -0800735 // location = /foo/bar/baz.jar
Richard Uhler63434112015-03-16 14:32:16 -0700736 // odex_location = /foo/bar/oat/<isa>/baz.odex
Richard Uhler66d874d2015-01-15 09:37:19 -0800737
Richard Uhler63434112015-03-16 14:32:16 -0700738 // Find the directory portion of the dex location and add the oat/<isa>
739 // directory.
Richard Uhler66d874d2015-01-15 09:37:19 -0800740 size_t pos = location.rfind('/');
741 if (pos == std::string::npos) {
742 *error_msg = "Dex location " + location + " has no directory.";
743 return false;
744 }
745 std::string dir = location.substr(0, pos+1);
Richard Uhler63434112015-03-16 14:32:16 -0700746 dir += "oat/" + std::string(GetInstructionSetString(isa));
Richard Uhler66d874d2015-01-15 09:37:19 -0800747
748 // Find the file portion of the dex location.
749 std::string file;
750 if (pos == std::string::npos) {
751 file = location;
752 } else {
753 file = location.substr(pos+1);
754 }
755
756 // Get the base part of the file without the extension.
757 pos = file.rfind('.');
758 if (pos == std::string::npos) {
759 *error_msg = "Dex location " + location + " has no extension.";
760 return false;
761 }
762 std::string base = file.substr(0, pos);
763
764 *odex_filename = dir + "/" + base + ".odex";
765 return true;
766}
767
768std::string OatFileAssistant::DalvikCacheDirectory() {
769 // Note: We don't cache this, because it will only be called once by
770 // OatFileName, and we don't care about the performance of the profiling
771 // code, which isn't used in practice.
772
773 // TODO: The work done in GetDalvikCache is overkill for what we need.
774 // Ideally a new API for getting the DalvikCacheDirectory the way we want
775 // (without existence testing, creation, or death) is provided with the rest
776 // of the GetDalvikCache family of functions. Until such an API is in place,
777 // we use GetDalvikCache to avoid duplicating the logic for determining the
778 // dalvik cache directory.
779 std::string result;
780 bool have_android_data;
781 bool dalvik_cache_exists;
782 bool is_global_cache;
783 GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache);
784 return result;
785}
786
787std::string OatFileAssistant::ProfileFileName() {
788 if (package_name_ != nullptr) {
789 return DalvikCacheDirectory() + std::string("profiles/") + package_name_;
790 }
791 return "";
792}
793
794std::string OatFileAssistant::OldProfileFileName() {
795 std::string profile_name = ProfileFileName();
796 if (profile_name.empty()) {
797 return "";
798 }
799 return profile_name + "@old";
800}
801
802std::string OatFileAssistant::ImageLocation() {
803 Runtime* runtime = Runtime::Current();
804 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
805 if (image_space == nullptr) {
806 return "";
807 }
808 return image_space->GetImageLocation();
809}
810
811const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
812 if (!required_dex_checksum_attempted) {
813 required_dex_checksum_attempted = true;
814 required_dex_checksum_found = false;
815 std::string error_msg;
816 CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location";
817 if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum, &error_msg)) {
818 required_dex_checksum_found = true;
819 } else {
820 // This can happen if the original dex file has been stripped from the
821 // apk.
822 VLOG(oat) << "OatFileAssistant: " << error_msg;
823
824 // Get the checksum from the odex if we can.
825 const OatFile* odex_file = GetOdexFile();
826 if (odex_file != nullptr) {
827 const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(
828 dex_location_, nullptr, false);
829 if (odex_dex_file != nullptr) {
830 cached_required_dex_checksum = odex_dex_file->GetDexFileLocationChecksum();
831 required_dex_checksum_found = true;
832 }
833 }
834 }
835 }
836 return required_dex_checksum_found ? &cached_required_dex_checksum : nullptr;
837}
838
839const OatFile* OatFileAssistant::GetOdexFile() {
840 CHECK(!oat_file_released_) << "OdexFile called after oat file released.";
841 if (!odex_file_load_attempted_) {
842 odex_file_load_attempted_ = true;
843 if (OdexFileName() != nullptr) {
844 const std::string& odex_file_name = *OdexFileName();
845 std::string error_msg;
846 cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(),
847 odex_file_name.c_str(), nullptr, nullptr, load_executable_,
Richard Uhlere5fed032015-03-18 08:21:11 -0700848 dex_location_, &error_msg));
Richard Uhler66d874d2015-01-15 09:37:19 -0800849 if (cached_odex_file_.get() == nullptr) {
850 VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file "
851 << odex_file_name << ": " << error_msg;
852 }
853 }
854 }
855 return cached_odex_file_.get();
856}
857
858void OatFileAssistant::ClearOdexFileCache() {
859 odex_file_load_attempted_ = false;
860 cached_odex_file_.reset();
861 odex_file_is_out_of_date_attempted_ = false;
862 odex_file_is_up_to_date_attempted_ = false;
863}
864
865const OatFile* OatFileAssistant::GetOatFile() {
866 CHECK(!oat_file_released_) << "OatFile called after oat file released.";
867 if (!oat_file_load_attempted_) {
868 oat_file_load_attempted_ = true;
869 if (OatFileName() != nullptr) {
870 const std::string& oat_file_name = *OatFileName();
871 std::string error_msg;
872 cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(),
Richard Uhlere5fed032015-03-18 08:21:11 -0700873 oat_file_name.c_str(), nullptr, nullptr, load_executable_,
874 dex_location_, &error_msg));
Richard Uhler66d874d2015-01-15 09:37:19 -0800875 if (cached_oat_file_.get() == nullptr) {
876 VLOG(oat) << "OatFileAssistant test for existing oat file "
877 << oat_file_name << ": " << error_msg;
878 }
879 }
880 }
881 return cached_oat_file_.get();
882}
883
884void OatFileAssistant::ClearOatFileCache() {
885 oat_file_load_attempted_ = false;
886 cached_oat_file_.reset();
887 oat_file_is_out_of_date_attempted_ = false;
888 oat_file_is_up_to_date_attempted_ = false;
889}
890
891const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
892 if (!image_info_load_attempted_) {
893 image_info_load_attempted_ = true;
894
895 Runtime* runtime = Runtime::Current();
896 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
897 if (image_space != nullptr) {
898 cached_image_info_.location = image_space->GetImageLocation();
899
900 if (isa_ == kRuntimeISA) {
901 const ImageHeader& image_header = image_space->GetImageHeader();
902 cached_image_info_.oat_checksum = image_header.GetOatChecksum();
903 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
904 cached_image_info_.patch_delta = image_header.GetPatchDelta();
905 } else {
906 std::unique_ptr<ImageHeader> image_header(
907 gc::space::ImageSpace::ReadImageHeaderOrDie(
908 cached_image_info_.location.c_str(), isa_));
909 cached_image_info_.oat_checksum = image_header->GetOatChecksum();
910 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin());
911 cached_image_info_.patch_delta = image_header->GetPatchDelta();
912 }
913 }
914 image_info_load_succeeded_ = (image_space != nullptr);
915 }
916 return image_info_load_succeeded_ ? &cached_image_info_ : nullptr;
917}
918
919ProfileFile* OatFileAssistant::GetProfile() {
920 if (!profile_load_attempted_) {
921 CHECK(package_name_ != nullptr)
922 << "pakage_name_ is nullptr: "
923 << "profile_load_attempted_ should have been true";
924 profile_load_attempted_ = true;
925 std::string profile_name = ProfileFileName();
926 if (!profile_name.empty()) {
927 profile_load_succeeded_ = cached_profile_.LoadFile(profile_name);
928 }
929 }
930 return profile_load_succeeded_ ? &cached_profile_ : nullptr;
931}
932
933ProfileFile* OatFileAssistant::GetOldProfile() {
934 if (!old_profile_load_attempted_) {
935 CHECK(package_name_ != nullptr)
936 << "pakage_name_ is nullptr: "
937 << "old_profile_load_attempted_ should have been true";
938 old_profile_load_attempted_ = true;
939 std::string old_profile_name = OldProfileFileName();
940 if (!old_profile_name.empty()) {
941 old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name);
942 }
943 }
944 return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr;
945}
946
947} // namespace art
948