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 <sstream>
20
21 #include <sys/stat.h>
22 #include "zlib.h"
23
24 #include "android-base/file.h"
25 #include "android-base/stringprintf.h"
26 #include "android-base/strings.h"
27
28 #include "base/compiler_filter.h"
29 #include "base/file_utils.h"
30 #include "base/logging.h" // For VLOG.
31 #include "base/macros.h"
32 #include "base/os.h"
33 #include "base/stl_util.h"
34 #include "base/string_view_cpp20.h"
35 #include "base/systrace.h"
36 #include "base/utils.h"
37 #include "base/zip_archive.h"
38 #include "class_linker.h"
39 #include "class_loader_context.h"
40 #include "dex/art_dex_file_loader.h"
41 #include "dex/dex_file_loader.h"
42 #include "exec_utils.h"
43 #include "gc/heap.h"
44 #include "gc/space/image_space.h"
45 #include "image.h"
46 #include "oat.h"
47 #include "runtime.h"
48 #include "scoped_thread_state_change-inl.h"
49 #include "vdex_file.h"
50
51 namespace art {
52
53 using android::base::StringPrintf;
54
55 static constexpr const char* kAnonymousDexPrefix = "Anonymous-DexFile@";
56 static constexpr const char* kVdexExtension = ".vdex";
57 static constexpr const char* kDmExtension = ".dm";
58
operator <<(std::ostream & stream,const OatFileAssistant::OatStatus status)59 std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status) {
60 switch (status) {
61 case OatFileAssistant::kOatCannotOpen:
62 stream << "kOatCannotOpen";
63 break;
64 case OatFileAssistant::kOatDexOutOfDate:
65 stream << "kOatDexOutOfDate";
66 break;
67 case OatFileAssistant::kOatBootImageOutOfDate:
68 stream << "kOatBootImageOutOfDate";
69 break;
70 case OatFileAssistant::kOatUpToDate:
71 stream << "kOatUpToDate";
72 break;
73 case OatFileAssistant::kOatContextOutOfDate:
74 stream << "kOaContextOutOfDate";
75 break;
76 }
77
78 return stream;
79 }
80
OatFileAssistant(const char * dex_location,const InstructionSet isa,ClassLoaderContext * context,bool load_executable,bool only_load_trusted_executable)81 OatFileAssistant::OatFileAssistant(const char* dex_location,
82 const InstructionSet isa,
83 ClassLoaderContext* context,
84 bool load_executable,
85 bool only_load_trusted_executable)
86 : OatFileAssistant(dex_location,
87 isa,
88 context,
89 load_executable,
90 only_load_trusted_executable,
91 /*vdex_fd=*/ -1,
92 /*oat_fd=*/ -1,
93 /*zip_fd=*/ -1) {}
94
95
OatFileAssistant(const char * dex_location,const InstructionSet isa,ClassLoaderContext * context,bool load_executable,bool only_load_trusted_executable,int vdex_fd,int oat_fd,int zip_fd)96 OatFileAssistant::OatFileAssistant(const char* dex_location,
97 const InstructionSet isa,
98 ClassLoaderContext* context,
99 bool load_executable,
100 bool only_load_trusted_executable,
101 int vdex_fd,
102 int oat_fd,
103 int zip_fd)
104 : context_(context),
105 isa_(isa),
106 load_executable_(load_executable),
107 only_load_trusted_executable_(only_load_trusted_executable),
108 odex_(this, /*is_oat_location=*/ false),
109 oat_(this, /*is_oat_location=*/ true),
110 vdex_for_odex_(this, /*is_oat_location=*/ false),
111 vdex_for_oat_(this, /*is_oat_location=*/ true),
112 dm_for_odex_(this, /*is_oat_location=*/ false),
113 dm_for_oat_(this, /*is_oat_location=*/ true),
114 zip_fd_(zip_fd) {
115 CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
116 CHECK_IMPLIES(load_executable, context != nullptr) << "Loading executable without a context";
117
118 if (zip_fd < 0) {
119 CHECK_LE(oat_fd, 0) << "zip_fd must be provided with valid oat_fd. zip_fd=" << zip_fd
120 << " oat_fd=" << oat_fd;
121 CHECK_LE(vdex_fd, 0) << "zip_fd must be provided with valid vdex_fd. zip_fd=" << zip_fd
122 << " vdex_fd=" << vdex_fd;;
123 CHECK(!UseFdToReadFiles());
124 } else {
125 CHECK(UseFdToReadFiles());
126 }
127
128 dex_location_.assign(dex_location);
129
130 if (load_executable_ && isa != kRuntimeISA) {
131 LOG(WARNING) << "OatFileAssistant: Load executable specified, "
132 << "but isa is not kRuntimeISA. Will not attempt to load executable.";
133 load_executable_ = false;
134 }
135
136 // Get the odex filename.
137 std::string error_msg;
138 std::string odex_file_name;
139 if (DexLocationToOdexFilename(dex_location_, isa_, &odex_file_name, &error_msg)) {
140 odex_.Reset(odex_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd);
141 std::string vdex_file_name = GetVdexFilename(odex_file_name);
142 // We dup FDs as the odex_ will claim ownership.
143 vdex_for_odex_.Reset(vdex_file_name,
144 UseFdToReadFiles(),
145 DupCloexec(zip_fd),
146 DupCloexec(vdex_fd),
147 DupCloexec(oat_fd));
148
149 std::string dm_file_name = GetDmFilename(dex_location_);
150 dm_for_odex_.Reset(dm_file_name,
151 UseFdToReadFiles(),
152 DupCloexec(zip_fd),
153 DupCloexec(vdex_fd),
154 DupCloexec(oat_fd));
155 } else {
156 LOG(WARNING) << "Failed to determine odex file name: " << error_msg;
157 }
158
159 if (!UseFdToReadFiles()) {
160 // Get the oat filename.
161 std::string oat_file_name;
162 if (DexLocationToOatFilename(dex_location_, isa_, &oat_file_name, &error_msg)) {
163 oat_.Reset(oat_file_name, /*use_fd=*/ false);
164 std::string vdex_file_name = GetVdexFilename(oat_file_name);
165 vdex_for_oat_.Reset(vdex_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd);
166 std::string dm_file_name = GetDmFilename(dex_location);
167 dm_for_oat_.Reset(dm_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd);
168 } else {
169 LOG(WARNING) << "Failed to determine oat file name for dex location "
170 << dex_location_ << ": " << error_msg;
171 }
172 }
173
174 // Check if the dex directory is writable.
175 // This will be needed in most uses of OatFileAssistant and so it's OK to
176 // compute it eagerly. (the only use which will not make use of it is
177 // OatFileAssistant::GetStatusDump())
178 size_t pos = dex_location_.rfind('/');
179 if (pos == std::string::npos) {
180 LOG(WARNING) << "Failed to determine dex file parent directory: " << dex_location_;
181 } else if (!UseFdToReadFiles()) {
182 // We cannot test for parent access when using file descriptors. That's ok
183 // because in this case we will always pick the odex file anyway.
184 std::string parent = dex_location_.substr(0, pos);
185 if (access(parent.c_str(), W_OK) == 0) {
186 dex_parent_writable_ = true;
187 } else {
188 VLOG(oat) << "Dex parent of " << dex_location_ << " is not writable: " << strerror(errno);
189 }
190 }
191 }
192
UseFdToReadFiles()193 bool OatFileAssistant::UseFdToReadFiles() {
194 return zip_fd_ >= 0;
195 }
196
IsInBootClassPath()197 bool OatFileAssistant::IsInBootClassPath() {
198 // Note: We check the current boot class path, regardless of the ISA
199 // specified by the user. This is okay, because the boot class path should
200 // be the same for all ISAs.
201 // TODO: Can we verify the boot class path is the same for all ISAs?
202 Runtime* runtime = Runtime::Current();
203 ClassLinker* class_linker = runtime->GetClassLinker();
204 const auto& boot_class_path = class_linker->GetBootClassPath();
205 for (size_t i = 0; i < boot_class_path.size(); i++) {
206 if (boot_class_path[i]->GetLocation() == dex_location_) {
207 VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path";
208 return true;
209 }
210 }
211 return false;
212 }
213
GetDexOptNeeded(CompilerFilter::Filter target,bool profile_changed,bool downgrade)214 int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target,
215 bool profile_changed,
216 bool downgrade) {
217 OatFileInfo& info = GetBestInfo();
218 DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target,
219 profile_changed,
220 downgrade);
221 if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
222 return dexopt_needed;
223 }
224 return -dexopt_needed;
225 }
226
IsUpToDate()227 bool OatFileAssistant::IsUpToDate() {
228 return GetBestInfo().Status() == kOatUpToDate;
229 }
230
GetBestOatFile()231 std::unique_ptr<OatFile> OatFileAssistant::GetBestOatFile() {
232 return GetBestInfo().ReleaseFileForUse();
233 }
234
GetStatusDump()235 std::string OatFileAssistant::GetStatusDump() {
236 std::ostringstream status;
237 bool oat_file_exists = false;
238 bool odex_file_exists = false;
239 if (oat_.Status() != kOatCannotOpen) {
240 // If we can open the file, Filename should not return null.
241 CHECK(oat_.Filename() != nullptr);
242
243 oat_file_exists = true;
244 status << *oat_.Filename() << "[status=" << oat_.Status() << ", ";
245 const OatFile* file = oat_.GetFile();
246 if (file == nullptr) {
247 // If the file is null even though the status is not kOatCannotOpen, it
248 // means we must have a vdex file with no corresponding oat file. In
249 // this case we cannot determine the compilation filter. Indicate that
250 // we have only the vdex file instead.
251 status << "vdex-only";
252 } else {
253 status << "compilation_filter=" << CompilerFilter::NameOfFilter(file->GetCompilerFilter());
254 }
255 }
256
257 if (odex_.Status() != kOatCannotOpen) {
258 // If we can open the file, Filename should not return null.
259 CHECK(odex_.Filename() != nullptr);
260
261 odex_file_exists = true;
262 if (oat_file_exists) {
263 status << "] ";
264 }
265 status << *odex_.Filename() << "[status=" << odex_.Status() << ", ";
266 const OatFile* file = odex_.GetFile();
267 if (file == nullptr) {
268 status << "vdex-only";
269 } else {
270 status << "compilation_filter=" << CompilerFilter::NameOfFilter(file->GetCompilerFilter());
271 }
272 }
273
274 if (!oat_file_exists && !odex_file_exists) {
275 status << "invalid[";
276 }
277
278 status << "]";
279 return status.str();
280 }
281
LoadDexFiles(const OatFile & oat_file,const char * dex_location)282 std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
283 const OatFile &oat_file, const char *dex_location) {
284 std::vector<std::unique_ptr<const DexFile>> dex_files;
285 if (LoadDexFiles(oat_file, dex_location, &dex_files)) {
286 return dex_files;
287 } else {
288 return std::vector<std::unique_ptr<const DexFile>>();
289 }
290 }
291
LoadDexFiles(const OatFile & oat_file,const std::string & dex_location,std::vector<std::unique_ptr<const DexFile>> * out_dex_files)292 bool OatFileAssistant::LoadDexFiles(
293 const OatFile &oat_file,
294 const std::string& dex_location,
295 std::vector<std::unique_ptr<const DexFile>>* out_dex_files) {
296 // Load the main dex file.
297 std::string error_msg;
298 const OatDexFile* oat_dex_file = oat_file.GetOatDexFile(
299 dex_location.c_str(), nullptr, &error_msg);
300 if (oat_dex_file == nullptr) {
301 LOG(WARNING) << error_msg;
302 return false;
303 }
304
305 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg);
306 if (dex_file.get() == nullptr) {
307 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
308 return false;
309 }
310 out_dex_files->push_back(std::move(dex_file));
311
312 // Load the rest of the multidex entries
313 for (size_t i = 1;; i++) {
314 std::string multidex_dex_location = DexFileLoader::GetMultiDexLocation(i, dex_location.c_str());
315 oat_dex_file = oat_file.GetOatDexFile(multidex_dex_location.c_str(), nullptr);
316 if (oat_dex_file == nullptr) {
317 // There are no more multidex entries to load.
318 break;
319 }
320
321 dex_file = oat_dex_file->OpenDexFile(&error_msg);
322 if (dex_file.get() == nullptr) {
323 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg;
324 return false;
325 }
326 out_dex_files->push_back(std::move(dex_file));
327 }
328 return true;
329 }
330
HasDexFiles()331 bool OatFileAssistant::HasDexFiles() {
332 ScopedTrace trace("HasDexFiles");
333 // Ensure GetRequiredDexChecksums has been run so that
334 // has_original_dex_files_ is initialized. We don't care about the result of
335 // GetRequiredDexChecksums.
336 GetRequiredDexChecksums();
337 return has_original_dex_files_;
338 }
339
OdexFileStatus()340 OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() {
341 return odex_.Status();
342 }
343
OatFileStatus()344 OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() {
345 return oat_.Status();
346 }
347
DexChecksumUpToDate(const VdexFile & file,std::string * error_msg)348 bool OatFileAssistant::DexChecksumUpToDate(const VdexFile& file, std::string* error_msg) {
349 ScopedTrace trace("DexChecksumUpToDate(vdex)");
350 const std::vector<uint32_t>* required_dex_checksums = GetRequiredDexChecksums();
351 if (required_dex_checksums == nullptr) {
352 LOG(WARNING) << "Required dex checksums not found. Assuming dex checksums are up to date.";
353 return true;
354 }
355
356 uint32_t number_of_dex_files = file.GetNumberOfDexFiles();
357 if (required_dex_checksums->size() != number_of_dex_files) {
358 *error_msg = StringPrintf("expected %zu dex files but found %u",
359 required_dex_checksums->size(),
360 number_of_dex_files);
361 return false;
362 }
363
364 for (uint32_t i = 0; i < number_of_dex_files; i++) {
365 uint32_t expected_checksum = (*required_dex_checksums)[i];
366 uint32_t actual_checksum = file.GetLocationChecksum(i);
367 if (expected_checksum != actual_checksum) {
368 std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
369 *error_msg = StringPrintf("Dex checksum does not match for dex: %s."
370 "Expected: %u, actual: %u",
371 dex.c_str(),
372 expected_checksum,
373 actual_checksum);
374 return false;
375 }
376 }
377
378 return true;
379 }
380
DexChecksumUpToDate(const OatFile & file,std::string * error_msg)381 bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* error_msg) {
382 ScopedTrace trace("DexChecksumUpToDate(oat)");
383 const std::vector<uint32_t>* required_dex_checksums = GetRequiredDexChecksums();
384 if (required_dex_checksums == nullptr) {
385 LOG(WARNING) << "Required dex checksums not found. Assuming dex checksums are up to date.";
386 return true;
387 }
388
389 uint32_t number_of_dex_files = file.GetOatHeader().GetDexFileCount();
390 if (required_dex_checksums->size() != number_of_dex_files) {
391 *error_msg = StringPrintf("expected %zu dex files but found %u",
392 required_dex_checksums->size(),
393 number_of_dex_files);
394 return false;
395 }
396
397 for (uint32_t i = 0; i < number_of_dex_files; i++) {
398 std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str());
399 uint32_t expected_checksum = (*required_dex_checksums)[i];
400 const OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str(), nullptr);
401 if (oat_dex_file == nullptr) {
402 *error_msg = StringPrintf("failed to find %s in %s", dex.c_str(), file.GetLocation().c_str());
403 return false;
404 }
405 uint32_t actual_checksum = oat_dex_file->GetDexFileLocationChecksum();
406 if (expected_checksum != actual_checksum) {
407 VLOG(oat) << "Dex checksum does not match for dex: " << dex
408 << ". Expected: " << expected_checksum
409 << ", Actual: " << actual_checksum;
410 return false;
411 }
412 }
413 return true;
414 }
415
GivenOatFileStatus(const OatFile & file)416 OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
417 // Verify the ART_USE_READ_BARRIER state.
418 // TODO: Don't fully reject files due to read barrier state. If they contain
419 // compiled code and are otherwise okay, we should return something like
420 // kOatRelocationOutOfDate. If they don't contain compiled code, the read
421 // barrier state doesn't matter.
422 const bool is_cc = file.GetOatHeader().IsConcurrentCopying();
423 constexpr bool kRuntimeIsCC = kUseReadBarrier;
424 if (is_cc != kRuntimeIsCC) {
425 return kOatCannotOpen;
426 }
427
428 // Verify the dex checksum.
429 std::string error_msg;
430 VdexFile* vdex = file.GetVdexFile();
431 if (!DexChecksumUpToDate(*vdex, &error_msg)) {
432 LOG(ERROR) << error_msg;
433 return kOatDexOutOfDate;
434 }
435
436 CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
437
438 // Verify the image checksum
439 if (file.IsBackedByVdexOnly()) {
440 VLOG(oat) << "Image checksum test skipped for vdex file " << file.GetLocation();
441 } else if (CompilerFilter::DependsOnImageChecksum(current_compiler_filter)) {
442 if (!ValidateBootClassPathChecksums(file)) {
443 VLOG(oat) << "Oat image checksum does not match image checksum.";
444 return kOatBootImageOutOfDate;
445 }
446 if (!gc::space::ImageSpace::ValidateApexVersions(file, &error_msg)) {
447 VLOG(oat) << error_msg;
448 return kOatBootImageOutOfDate;
449 }
450 } else {
451 VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
452 }
453
454 // zip_file_only_contains_uncompressed_dex_ is only set during fetching the dex checksums.
455 DCHECK(required_dex_checksums_attempted_);
456 if (only_load_trusted_executable_ &&
457 !LocationIsTrusted(file.GetLocation(), !Runtime::Current()->DenyArtApexDataFiles()) &&
458 file.ContainsDexCode() &&
459 zip_file_only_contains_uncompressed_dex_) {
460 LOG(ERROR) << "Not loading "
461 << dex_location_
462 << ": oat file has dex code, but APK has uncompressed dex code";
463 return kOatDexOutOfDate;
464 }
465
466 if (!ClassLoaderContextIsOkay(file)) {
467 return kOatContextOutOfDate;
468 }
469
470 return kOatUpToDate;
471 }
472
AnonymousDexVdexLocation(const std::vector<const DexFile::Header * > & headers,InstructionSet isa,std::string * dex_location,std::string * vdex_filename)473 bool OatFileAssistant::AnonymousDexVdexLocation(const std::vector<const DexFile::Header*>& headers,
474 InstructionSet isa,
475 /* out */ std::string* dex_location,
476 /* out */ std::string* vdex_filename) {
477 uint32_t checksum = adler32(0L, Z_NULL, 0);
478 for (const DexFile::Header* header : headers) {
479 checksum = adler32_combine(checksum,
480 header->checksum_,
481 header->file_size_ - DexFile::kNumNonChecksumBytes);
482 }
483
484 const std::string& data_dir = Runtime::Current()->GetProcessDataDirectory();
485 if (data_dir.empty() || Runtime::Current()->IsZygote()) {
486 *dex_location = StringPrintf("%s%u", kAnonymousDexPrefix, checksum);
487 return false;
488 }
489 *dex_location = StringPrintf("%s/%s%u.jar", data_dir.c_str(), kAnonymousDexPrefix, checksum);
490
491 std::string odex_filename;
492 std::string error_msg;
493 if (!DexLocationToOdexFilename(*dex_location, isa, &odex_filename, &error_msg)) {
494 LOG(WARNING) << "Could not get odex filename for " << *dex_location << ": " << error_msg;
495 return false;
496 }
497
498 *vdex_filename = GetVdexFilename(odex_filename);
499 return true;
500 }
501
IsAnonymousVdexBasename(const std::string & basename)502 bool OatFileAssistant::IsAnonymousVdexBasename(const std::string& basename) {
503 DCHECK(basename.find('/') == std::string::npos);
504 // `basename` must have format: <kAnonymousDexPrefix><checksum><kVdexExtension>
505 if (basename.size() < strlen(kAnonymousDexPrefix) + strlen(kVdexExtension) + 1 ||
506 !android::base::StartsWith(basename.c_str(), kAnonymousDexPrefix) ||
507 !android::base::EndsWith(basename, kVdexExtension)) {
508 return false;
509 }
510 // Check that all characters between the prefix and extension are decimal digits.
511 for (size_t i = strlen(kAnonymousDexPrefix); i < basename.size() - strlen(kVdexExtension); ++i) {
512 if (!std::isdigit(basename[i])) {
513 return false;
514 }
515 }
516 return true;
517 }
518
DexLocationToOdexFilename(const std::string & location,InstructionSet isa,std::string * odex_filename,std::string * error_msg)519 bool OatFileAssistant::DexLocationToOdexFilename(const std::string& location,
520 InstructionSet isa,
521 std::string* odex_filename,
522 std::string* error_msg) {
523 CHECK(odex_filename != nullptr);
524 CHECK(error_msg != nullptr);
525
526 // For a DEX file on /apex, check if there is an odex file on /system. If so, and the file exists,
527 // use it.
528 if (LocationIsOnApex(location)) {
529 const std::string system_file = GetSystemOdexFilenameForApex(location, isa);
530 if (OS::FileExists(system_file.c_str(), /*check_file_type=*/true)) {
531 *odex_filename = system_file;
532 return true;
533 } else if (errno != ENOENT) {
534 PLOG(ERROR) << "Could not check odex file " << system_file;
535 }
536 }
537
538 // The odex file name is formed by replacing the dex_location extension with
539 // .odex and inserting an oat/<isa> directory. For example:
540 // location = /foo/bar/baz.jar
541 // odex_location = /foo/bar/oat/<isa>/baz.odex
542
543 // Find the directory portion of the dex location and add the oat/<isa>
544 // directory.
545 size_t pos = location.rfind('/');
546 if (pos == std::string::npos) {
547 *error_msg = "Dex location " + location + " has no directory.";
548 return false;
549 }
550 std::string dir = location.substr(0, pos+1);
551 // Add the oat directory.
552 dir += "oat";
553
554 // Add the isa directory
555 dir += "/" + std::string(GetInstructionSetString(isa));
556
557 // Get the base part of the file without the extension.
558 std::string file = location.substr(pos+1);
559 pos = file.rfind('.');
560 if (pos == std::string::npos) {
561 *error_msg = "Dex location " + location + " has no extension.";
562 return false;
563 }
564 std::string base = file.substr(0, pos);
565
566 *odex_filename = dir + "/" + base + ".odex";
567 return true;
568 }
569
DexLocationToOatFilename(const std::string & location,InstructionSet isa,std::string * oat_filename,std::string * error_msg)570 bool OatFileAssistant::DexLocationToOatFilename(const std::string& location,
571 InstructionSet isa,
572 std::string* oat_filename,
573 std::string* error_msg) {
574 CHECK(oat_filename != nullptr);
575 CHECK(error_msg != nullptr);
576
577 // Check if `location` could have an oat file in the ART APEX data directory. If so, and the
578 // file exists, use it.
579 const std::string apex_data_file = GetApexDataOdexFilename(location, isa);
580 if (!apex_data_file.empty() && !Runtime::Current()->DenyArtApexDataFiles()) {
581 if (OS::FileExists(apex_data_file.c_str(), /*check_file_type=*/true)) {
582 *oat_filename = apex_data_file;
583 return true;
584 } else if (errno != ENOENT) {
585 PLOG(ERROR) << "Could not check odex file " << apex_data_file;
586 }
587 }
588
589 // If ANDROID_DATA is not set, return false instead of aborting.
590 // This can occur for preopt when using a class loader context.
591 if (GetAndroidDataSafe(error_msg).empty()) {
592 *error_msg = "GetAndroidDataSafe failed: " + *error_msg;
593 return false;
594 }
595
596 std::string dalvik_cache;
597 bool have_android_data = false;
598 bool dalvik_cache_exists = false;
599 bool is_global_cache = false;
600 GetDalvikCache(GetInstructionSetString(isa),
601 /*create_if_absent=*/ true,
602 &dalvik_cache,
603 &have_android_data,
604 &dalvik_cache_exists,
605 &is_global_cache);
606 if (!dalvik_cache_exists) {
607 *error_msg = "Dalvik cache directory does not exist";
608 return false;
609 }
610
611 // TODO: The oat file assistant should be the definitive place for
612 // determining the oat file name from the dex location, not
613 // GetDalvikCacheFilename.
614 return GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(), oat_filename, error_msg);
615 }
616
GetRequiredDexChecksums()617 const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums() {
618 if (!required_dex_checksums_attempted_) {
619 required_dex_checksums_attempted_ = true;
620 required_dex_checksums_found_ = false;
621 cached_required_dex_checksums_.clear();
622 std::string error_msg;
623 const ArtDexFileLoader dex_file_loader;
624 std::vector<std::string> dex_locations_ignored;
625 if (dex_file_loader.GetMultiDexChecksums(dex_location_.c_str(),
626 &cached_required_dex_checksums_,
627 &dex_locations_ignored,
628 &error_msg,
629 zip_fd_,
630 &zip_file_only_contains_uncompressed_dex_)) {
631 required_dex_checksums_found_ = true;
632 has_original_dex_files_ = true;
633 } else {
634 // The only valid case here is for APKs without dex files.
635 required_dex_checksums_found_ = false;
636 has_original_dex_files_ = false;
637 VLOG(oat) << "Could not get required checksum: " << error_msg;
638 }
639 }
640 return required_dex_checksums_found_ ? &cached_required_dex_checksums_ : nullptr;
641 }
642
ValidateBootClassPathChecksums(const OatFile & oat_file)643 bool OatFileAssistant::ValidateBootClassPathChecksums(const OatFile& oat_file) {
644 // Get the checksums and the BCP from the oat file.
645 const char* oat_boot_class_path_checksums =
646 oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
647 const char* oat_boot_class_path =
648 oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathKey);
649 if (oat_boot_class_path_checksums == nullptr || oat_boot_class_path == nullptr) {
650 return false;
651 }
652 std::string_view oat_boot_class_path_checksums_view(oat_boot_class_path_checksums);
653 std::string_view oat_boot_class_path_view(oat_boot_class_path);
654 if (oat_boot_class_path_view == cached_boot_class_path_ &&
655 oat_boot_class_path_checksums_view == cached_boot_class_path_checksums_) {
656 return true;
657 }
658
659 Runtime* runtime = Runtime::Current();
660 std::string error_msg;
661 bool result = false;
662 // Fast path when the runtime boot classpath cheksums and boot classpath
663 // locations directly match.
664 if (oat_boot_class_path_checksums_view == runtime->GetBootClassPathChecksums() &&
665 isa_ == kRuntimeISA &&
666 oat_boot_class_path_view == android::base::Join(runtime->GetBootClassPathLocations(), ":")) {
667 result = true;
668 } else {
669 result = gc::space::ImageSpace::VerifyBootClassPathChecksums(
670 oat_boot_class_path_checksums_view,
671 oat_boot_class_path_view,
672 ArrayRef<const std::string>(runtime->GetImageLocations()),
673 ArrayRef<const std::string>(runtime->GetBootClassPathLocations()),
674 ArrayRef<const std::string>(runtime->GetBootClassPath()),
675 ArrayRef<const int>(runtime->GetBootClassPathFds()),
676 isa_,
677 &error_msg);
678 }
679 if (!result) {
680 VLOG(oat) << "Failed to verify checksums of oat file " << oat_file.GetLocation()
681 << " error: " << error_msg;
682 return false;
683 }
684
685 // This checksum has been validated, so save it.
686 cached_boot_class_path_ = oat_boot_class_path_view;
687 cached_boot_class_path_checksums_ = oat_boot_class_path_checksums_view;
688 return true;
689 }
690
GetBestInfo()691 OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
692 ScopedTrace trace("GetBestInfo");
693 // TODO(calin): Document the side effects of class loading when
694 // running dalvikvm command line.
695 if (dex_parent_writable_ || UseFdToReadFiles()) {
696 // If the parent of the dex file is writable it means that we can
697 // create the odex file. In this case we unconditionally pick the odex
698 // as the best oat file. This corresponds to the regular use case when
699 // apps gets installed or when they load private, secondary dex file.
700 // For apps on the system partition the odex location will not be
701 // writable and thus the oat location might be more up to date.
702
703 // If the odex is not useable, and we have a useable vdex, return the vdex
704 // instead.
705 if (!odex_.IsUseable()) {
706 if (vdex_for_odex_.IsUseable()) {
707 return vdex_for_odex_;
708 } else if (dm_for_odex_.IsUseable()) {
709 return dm_for_odex_;
710 }
711 }
712 return odex_;
713 }
714
715 // We cannot write to the odex location. This must be a system app.
716
717 // If the oat location is useable take it.
718 if (oat_.IsUseable()) {
719 return oat_;
720 }
721
722 // The oat file is not useable but the odex file might be up to date.
723 // This is an indication that we are dealing with an up to date prebuilt
724 // (that doesn't need relocation).
725 if (odex_.IsUseable()) {
726 return odex_;
727 }
728
729 // Look for a useable vdex file.
730 if (vdex_for_oat_.IsUseable()) {
731 return vdex_for_oat_;
732 }
733 if (vdex_for_odex_.IsUseable()) {
734 return vdex_for_odex_;
735 }
736 if (dm_for_oat_.IsUseable()) {
737 return dm_for_oat_;
738 }
739 if (dm_for_odex_.IsUseable()) {
740 return dm_for_odex_;
741 }
742
743 // We got into the worst situation here:
744 // - the oat location is not useable
745 // - the prebuild odex location is not up to date
746 // - the vdex-only file is not useable
747 // - and we don't have the original dex file anymore (stripped).
748 // Pick the odex if it exists, or the oat if not.
749 return (odex_.Status() == kOatCannotOpen) ? oat_ : odex_;
750 }
751
OpenImageSpace(const OatFile * oat_file)752 std::unique_ptr<gc::space::ImageSpace> OatFileAssistant::OpenImageSpace(const OatFile* oat_file) {
753 DCHECK(oat_file != nullptr);
754 std::string art_file = ReplaceFileExtension(oat_file->GetLocation(), "art");
755 if (art_file.empty()) {
756 return nullptr;
757 }
758 std::string error_msg;
759 ScopedObjectAccess soa(Thread::Current());
760 std::unique_ptr<gc::space::ImageSpace> ret =
761 gc::space::ImageSpace::CreateFromAppImage(art_file.c_str(), oat_file, &error_msg);
762 if (ret == nullptr && (VLOG_IS_ON(image) || OS::FileExists(art_file.c_str()))) {
763 LOG(INFO) << "Failed to open app image " << art_file.c_str() << " " << error_msg;
764 }
765 return ret;
766 }
767
OatFileInfo(OatFileAssistant * oat_file_assistant,bool is_oat_location)768 OatFileAssistant::OatFileInfo::OatFileInfo(OatFileAssistant* oat_file_assistant,
769 bool is_oat_location)
770 : oat_file_assistant_(oat_file_assistant), is_oat_location_(is_oat_location)
771 {}
772
IsOatLocation()773 bool OatFileAssistant::OatFileInfo::IsOatLocation() {
774 return is_oat_location_;
775 }
776
Filename()777 const std::string* OatFileAssistant::OatFileInfo::Filename() {
778 return filename_provided_ ? &filename_ : nullptr;
779 }
780
IsUseable()781 bool OatFileAssistant::OatFileInfo::IsUseable() {
782 ScopedTrace trace("IsUseable");
783 switch (Status()) {
784 case kOatCannotOpen:
785 case kOatDexOutOfDate:
786 case kOatContextOutOfDate:
787 case kOatBootImageOutOfDate: return false;
788
789 case kOatUpToDate: return true;
790 }
791 UNREACHABLE();
792 }
793
Status()794 OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() {
795 ScopedTrace trace("Status");
796 if (!status_attempted_) {
797 status_attempted_ = true;
798 const OatFile* file = GetFile();
799 if (file == nullptr) {
800 status_ = kOatCannotOpen;
801 } else {
802 status_ = oat_file_assistant_->GivenOatFileStatus(*file);
803 VLOG(oat) << file->GetLocation() << " is " << status_
804 << " with filter " << file->GetCompilerFilter();
805 }
806 }
807 return status_;
808 }
809
GetDexOptNeeded(CompilerFilter::Filter target,bool profile_changed,bool downgrade)810 OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
811 CompilerFilter::Filter target,
812 bool profile_changed,
813 bool downgrade) {
814
815 if (IsUseable()) {
816 return CompilerFilterIsOkay(target, profile_changed, downgrade)
817 ? kNoDexOptNeeded
818 : kDex2OatForFilter;
819 }
820
821 if (Status() == kOatBootImageOutOfDate) {
822 return kDex2OatForBootImage;
823 }
824
825 if (oat_file_assistant_->HasDexFiles()) {
826 return kDex2OatFromScratch;
827 } else {
828 // No dex file, there is nothing we need to do.
829 return kNoDexOptNeeded;
830 }
831 }
832
GetFile()833 const OatFile* OatFileAssistant::OatFileInfo::GetFile() {
834 CHECK(!file_released_) << "GetFile called after oat file released.";
835 if (load_attempted_) {
836 return file_.get();
837 }
838 load_attempted_ = true;
839 if (!filename_provided_) {
840 return nullptr;
841 }
842
843 if (LocationIsOnArtApexData(filename_) && Runtime::Current()->DenyArtApexDataFiles()) {
844 LOG(WARNING) << "OatFileAssistant rejected file " << filename_
845 << ": ART apexdata is untrusted.";
846 return nullptr;
847 }
848
849 std::string error_msg;
850 bool executable = oat_file_assistant_->load_executable_;
851 if (android::base::EndsWith(filename_, kVdexExtension)) {
852 executable = false;
853 // Check to see if there is a vdex file we can make use of.
854 std::unique_ptr<VdexFile> vdex;
855 if (use_fd_) {
856 if (vdex_fd_ >= 0) {
857 struct stat s;
858 int rc = TEMP_FAILURE_RETRY(fstat(vdex_fd_, &s));
859 if (rc == -1) {
860 error_msg = StringPrintf("Failed getting length of the vdex file %s.", strerror(errno));
861 } else {
862 vdex = VdexFile::Open(vdex_fd_,
863 s.st_size,
864 filename_,
865 /*writable=*/ false,
866 /*low_4gb=*/ false,
867 &error_msg);
868 }
869 }
870 } else {
871 vdex = VdexFile::Open(filename_,
872 /*writable=*/ false,
873 /*low_4gb=*/ false,
874 &error_msg);
875 }
876 if (vdex == nullptr) {
877 VLOG(oat) << "unable to open vdex file " << filename_ << ": " << error_msg;
878 } else {
879 file_.reset(OatFile::OpenFromVdex(zip_fd_,
880 std::move(vdex),
881 oat_file_assistant_->dex_location_,
882 &error_msg));
883 }
884 } else if (android::base::EndsWith(filename_, kDmExtension)) {
885 executable = false;
886 // Check to see if there is a vdex file we can make use of.
887 std::unique_ptr<ZipArchive> dm_file(ZipArchive::Open(filename_.c_str(), &error_msg));
888 if (dm_file != nullptr) {
889 std::unique_ptr<VdexFile> vdex(VdexFile::OpenFromDm(filename_, *dm_file));
890 if (vdex != nullptr) {
891 file_.reset(OatFile::OpenFromVdex(zip_fd_,
892 std::move(vdex),
893 oat_file_assistant_->dex_location_,
894 &error_msg));
895 }
896 }
897 } else {
898 if (executable && oat_file_assistant_->only_load_trusted_executable_) {
899 executable = LocationIsTrusted(filename_, /*trust_art_apex_data_files=*/ true);
900 }
901 VLOG(oat) << "Loading " << filename_ << " with executable: " << executable;
902 if (use_fd_) {
903 if (oat_fd_ >= 0 && vdex_fd_ >= 0) {
904 ArrayRef<const std::string> dex_locations(&oat_file_assistant_->dex_location_,
905 /*size=*/ 1u);
906 file_.reset(OatFile::Open(zip_fd_,
907 vdex_fd_,
908 oat_fd_,
909 filename_.c_str(),
910 executable,
911 /*low_4gb=*/ false,
912 dex_locations,
913 /*dex_fds=*/ ArrayRef<const int>(),
914 /*reservation=*/ nullptr,
915 &error_msg));
916 }
917 } else {
918 file_.reset(OatFile::Open(/*zip_fd=*/ -1,
919 filename_.c_str(),
920 filename_.c_str(),
921 executable,
922 /*low_4gb=*/ false,
923 oat_file_assistant_->dex_location_,
924 &error_msg));
925 }
926 }
927 if (file_.get() == nullptr) {
928 VLOG(oat) << "OatFileAssistant test for existing oat file "
929 << filename_
930 << ": " << error_msg;
931 } else {
932 VLOG(oat) << "Successfully loaded " << filename_ << " with executable: " << executable;
933 }
934 return file_.get();
935 }
936
CompilerFilterIsOkay(CompilerFilter::Filter target,bool profile_changed,bool downgrade)937 bool OatFileAssistant::OatFileInfo::CompilerFilterIsOkay(
938 CompilerFilter::Filter target, bool profile_changed, bool downgrade) {
939 const OatFile* file = GetFile();
940 if (file == nullptr) {
941 return false;
942 }
943
944 CompilerFilter::Filter current = file->GetCompilerFilter();
945 if (profile_changed && CompilerFilter::DependsOnProfile(current)) {
946 VLOG(oat) << "Compiler filter not okay because Profile changed";
947 return false;
948 }
949
950 if (downgrade) {
951 return !CompilerFilter::IsBetter(current, target);
952 }
953
954 if (CompilerFilter::DependsOnImageChecksum(current) &&
955 CompilerFilter::IsAsGoodAs(current, target)) {
956 // If the oat file has been compiled without an image, and the runtime is
957 // now running with an image loaded from disk, return that we need to
958 // re-compile. The recompilation will generate a better oat file, and with an app
959 // image for profile guided compilation.
960 const char* oat_boot_class_path_checksums =
961 file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
962 if (oat_boot_class_path_checksums != nullptr &&
963 !StartsWith(oat_boot_class_path_checksums, "i") &&
964 !Runtime::Current()->HasImageWithProfile()) {
965 DCHECK(!file->GetOatHeader().RequiresImage());
966 return false;
967 }
968 }
969
970 return CompilerFilter::IsAsGoodAs(current, target);
971 }
972
ClassLoaderContextIsOkay(const OatFile & oat_file) const973 bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
974 if (oat_file.IsBackedByVdexOnly()) {
975 // Only a vdex file, we don't depend on the class loader context.
976 return true;
977 }
978
979 if (!CompilerFilter::IsVerificationEnabled(oat_file.GetCompilerFilter())) {
980 // If verification is not enabled we don't need to verify the class loader context and we
981 // assume it's ok.
982 return true;
983 }
984
985 if (context_ == nullptr) {
986 // When no class loader context is provided (which happens for deprecated
987 // DexFile APIs), just assume it is OK.
988 return true;
989 }
990
991 ClassLoaderContext::VerificationResult matches = context_->VerifyClassLoaderContextMatch(
992 oat_file.GetClassLoaderContext(),
993 /*verify_names=*/ true,
994 /*verify_checksums=*/ true);
995 if (matches == ClassLoaderContext::VerificationResult::kMismatch) {
996 VLOG(oat) << "ClassLoaderContext check failed. Context was "
997 << oat_file.GetClassLoaderContext()
998 << ". The expected context is "
999 << context_->EncodeContextForOatFile(android::base::Dirname(dex_location_));
1000 return false;
1001 }
1002 return true;
1003 }
1004
IsExecutable()1005 bool OatFileAssistant::OatFileInfo::IsExecutable() {
1006 const OatFile* file = GetFile();
1007 return (file != nullptr && file->IsExecutable());
1008 }
1009
Reset()1010 void OatFileAssistant::OatFileInfo::Reset() {
1011 load_attempted_ = false;
1012 file_.reset();
1013 status_attempted_ = false;
1014 }
1015
Reset(const std::string & filename,bool use_fd,int zip_fd,int vdex_fd,int oat_fd)1016 void OatFileAssistant::OatFileInfo::Reset(const std::string& filename,
1017 bool use_fd,
1018 int zip_fd,
1019 int vdex_fd,
1020 int oat_fd) {
1021 filename_provided_ = true;
1022 filename_ = filename;
1023 use_fd_ = use_fd;
1024 zip_fd_ = zip_fd;
1025 vdex_fd_ = vdex_fd;
1026 oat_fd_ = oat_fd;
1027 Reset();
1028 }
1029
ReleaseFile()1030 std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFile() {
1031 file_released_ = true;
1032 return std::move(file_);
1033 }
1034
ReleaseFileForUse()1035 std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() {
1036 ScopedTrace trace("ReleaseFileForUse");
1037 if (Status() == kOatUpToDate) {
1038 return ReleaseFile();
1039 }
1040
1041 return std::unique_ptr<OatFile>();
1042 }
1043
1044 // TODO(calin): we could provide a more refined status here
1045 // (e.g. run from uncompressed apk, run with vdex but not oat etc). It will allow us to
1046 // track more experiments but adds extra complexity.
GetOptimizationStatus(const std::string & filename,InstructionSet isa,std::string * out_compilation_filter,std::string * out_compilation_reason)1047 void OatFileAssistant::GetOptimizationStatus(
1048 const std::string& filename,
1049 InstructionSet isa,
1050 std::string* out_compilation_filter,
1051 std::string* out_compilation_reason) {
1052 // It may not be possible to load an oat file executable (e.g., selinux restrictions). Load
1053 // non-executable and check the status manually.
1054 OatFileAssistant oat_file_assistant(filename.c_str(),
1055 isa,
1056 /* context= */ nullptr,
1057 /*load_executable=*/ false);
1058 std::string out_odex_location; // unused
1059 std::string out_odex_status; // unused
1060 oat_file_assistant.GetOptimizationStatus(
1061 &out_odex_location,
1062 out_compilation_filter,
1063 out_compilation_reason,
1064 &out_odex_status);
1065 }
1066
GetOptimizationStatus(std::string * out_odex_location,std::string * out_compilation_filter,std::string * out_compilation_reason,std::string * out_odex_status)1067 void OatFileAssistant::GetOptimizationStatus(
1068 std::string* out_odex_location,
1069 std::string* out_compilation_filter,
1070 std::string* out_compilation_reason,
1071 std::string* out_odex_status) {
1072 OatFileInfo& oat_file_info = GetBestInfo();
1073 const OatFile* oat_file = GetBestInfo().GetFile();
1074
1075 if (oat_file == nullptr) {
1076 *out_odex_location = "error";
1077 *out_compilation_filter = "run-from-apk";
1078 *out_compilation_reason = "unknown";
1079 // This mostly happens when we cannot open the oat file.
1080 // Note that it's different than kOatCannotOpen.
1081 // TODO: The design of getting the BestInfo is not ideal,
1082 // as it's not very clear what's the difference between
1083 // a nullptr and kOatcannotOpen. The logic should be revised
1084 // and improved.
1085 *out_odex_status = "io-error-no-oat";
1086 return;
1087 }
1088
1089 *out_odex_location = oat_file->GetLocation();
1090 OatStatus status = oat_file_info.Status();
1091 const char* reason = oat_file->GetCompilationReason();
1092 *out_compilation_reason = reason == nullptr ? "unknown" : reason;
1093 switch (status) {
1094 case kOatUpToDate:
1095 *out_compilation_filter = CompilerFilter::NameOfFilter(oat_file->GetCompilerFilter());
1096 *out_odex_status = "up-to-date";
1097 return;
1098
1099 case kOatCannotOpen: // This should never happen, but be robust.
1100 *out_compilation_filter = "error";
1101 *out_compilation_reason = "error";
1102 // This mostly happens when we cannot open the vdex file,
1103 // or the file is corrupt.
1104 *out_odex_status = "io-error-or-corruption";
1105 return;
1106
1107 case kOatBootImageOutOfDate:
1108 *out_compilation_filter = "run-from-apk-fallback";
1109 *out_odex_status = "boot-image-more-recent";
1110 return;
1111
1112 case kOatContextOutOfDate:
1113 *out_compilation_filter = "run-from-apk-fallback";
1114 *out_odex_status = "context-mismatch";
1115 return;
1116
1117 case kOatDexOutOfDate:
1118 *out_compilation_filter = "run-from-apk-fallback";
1119 *out_odex_status = "apk-more-recent";
1120 return;
1121 }
1122 LOG(FATAL) << "Unreachable";
1123 UNREACHABLE();
1124 }
1125
1126 } // namespace art
1127