// Check early that the result of compilation can be written
// 创建oat文件
std::unique_ptr<File> oat_file;
bool create_file = !oat_unstripped.empty(); // as opposed to using open file descriptor
if (create_file) {
oat_file.reset(OS::CreateEmptyFile(oat_unstripped.c_str()));
if (oat_location.empty()) {
oat_location = oat_filename;
}
} else {
oat_file.reset(new File(oat_fd, oat_location));
oat_file->DisableAutoClose();
}
if (oat_file.get() == nullptr) {
PLOG(ERROR) << "Failed to create oat file: " << oat_location;
return EXIT_FAILURE;
}
if (create_file && fchmod(oat_file->Fd(), 0644) != 0) {
PLOG(ERROR) << "Failed to make oat file world readable: " << oat_location;
return EXIT_FAILURE;
}
timings.StartSplit("dex2oat Setup");
LOG(INFO) << CommandLine();
Runtime::Options runtime_options;
std::vector<const DexFile*> boot_class_path;
if (boot_image_option.empty()) {
size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
if (failure_count > 0) {
LOG(ERROR) << "Failed to open some dex files: " << failure_count;
return EXIT_FAILURE;
}
runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
} else {
runtime_options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
}
for (size_t i = 0; i < runtime_args.size(); i++) {
runtime_options.push_back(std::make_pair(runtime_args[i], nullptr));
}
VerificationResults verification_results(&compiler_options);
DexFileToMethodInlinerMap method_inliner_map;
CompilerCallbacksImpl callbacks(&verification_results, &method_inliner_map);
runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks));
runtime_options.push_back(
std::make_pair("imageinstructionset",
reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
Dex2Oat* p_dex2oat;
if (!Dex2Oat::Create(&p_dex2oat,
runtime_options,
compiler_options,
compiler_kind,
instruction_set,
instruction_set_features,
&verification_results,
&method_inliner_map,
thread_count)) {
LOG(ERROR) << "Failed to create dex2oat";
return EXIT_FAILURE;
}
std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);
// TODO: Not sure whether it's a good idea to allow anything else but the runtime option in
// this case at all, as we'll have to throw away produced code for a mismatch.
// 参数判断
if (!has_explicit_checks_options) {
if (instruction_set == kRuntimeISA) {
Runtime* runtime = Runtime::Current();
compiler_options.SetExplicitNullChecks(runtime->ExplicitNullChecks());
compiler_options.SetExplicitStackOverflowChecks(runtime->ExplicitStackOverflowChecks());
compiler_options.SetExplicitSuspendChecks(runtime->ExplicitSuspendChecks());
}
}
// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now so that we don't starve GC.
// 线程悬挂,因此不触发GC
Thread* self = Thread::Current();
self->TransitionFromRunnableToSuspended(kNative);
// If we're doing the image, override the compiler filter to force full compilation. Must be
// done ahead of WellKnownClasses::Init that causes verification. Note: doesn't force
// compilation of class initializers.
// Whilst we're in native take the opportunity to initialize well known classes.
// init 常用类
WellKnownClasses::Init(self->GetJniEnv());
// If --image-classes was specified, calculate the full list of classes to include in the image
// 编译目标
std::unique_ptr<CompilerDriver::DescriptorSet> image_classes(nullptr);
if (image_classes_filename != nullptr) {
std::string error_msg;
if (image_classes_zip_filename != nullptr) {
image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
image_classes_filename,
&error_msg));
} else {
//如果classes filename不为空
//将class文件编译进image
image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
}
if (image_classes.get() == nullptr) {
LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename <<
"': " << error_msg;
return EXIT_FAILURE;
}
} else if (image) {
image_classes.reset(new CompilerDriver::DescriptorSet);
}
std::vector<const DexFile*> dex_files;
if (boot_image_option.empty()) {
dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath();
} else {
// image初始化的option
// 读取dexfile
if (dex_filenames.empty()) {
ATRACE_BEGIN("Opening zip archive from file descriptor");
std::string error_msg;
std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(),
&error_msg));
if (zip_archive.get() == nullptr) {
LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': "
<< error_msg;
return EXIT_FAILURE;
}
const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location, &error_msg);
if (dex_file == nullptr) {
LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
<< "': " << error_msg;
return EXIT_FAILURE;
}
dex_files.push_back(dex_file);
ATRACE_END();
} else {
size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files);
if (failure_count > 0) {
LOG(ERROR) << "Failed to open some dex files: " << failure_count;
return EXIT_FAILURE;
}
}
//dex file保存
const bool kSaveDexInput = false;
if (kSaveDexInput) {
for (size_t i = 0; i < dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i));
std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
if (tmp_file.get() == nullptr) {
PLOG(ERROR) << "Failed to open file " << tmp_file_name
<< ". Try: adb shell chmod 777 /data/local/tmp";
continue;
}
tmp_file->WriteFully(dex_file->Begin(), dex_file->Size());
LOG(INFO) << "Wrote input to " << tmp_file_name;
}
}
}
// Ensure opened dex files are writable for dex-to-dex transformations.
for (const auto& dex_file : dex_files) {
if (!dex_file->EnableWrite()) {
PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
}
}
/*
* If we're not in interpret-only or verify-none mode, go ahead and compile small applications.
* Don't bother to check if we're doing the image.
*/
if (!image && compiler_options.IsCompilationEnabled()) {
size_t num_methods = 0;
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
num_methods += dex_file->NumMethodIds();
}
//如果dex中方法少的话,编译选项改为speed
if (num_methods <= compiler_options.GetNumDexMethodsThreshold()) {
compiler_options.SetCompilerFilter(CompilerOptions::kSpeed);
VLOG(compiler) << "Below method threshold, compiling anyways";
}
}
//创建oat文件
std::unique_ptr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
android_root,
is_host,
dex_files,
oat_file.get(),
bitcode_filename,
image,
image_classes,
dump_stats,
dump_passes,
timings,
compiler_phases_timings,
profile_file));
if (compiler.get() == nullptr) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
return EXIT_FAILURE;
}
VLOG(compiler) << "Oat file written successfully (unstripped): " << oat_location;
// Notes on the interleaving of creating the image and oat file to
// ensure the references between the two are correct.
//
// Currently we have a memory layout that looks something like this:
//
// +--------------+
// | image |
// +--------------+
// | boot oat |
// +--------------+
// | alloc spaces |
// +--------------+
//
// There are several constraints on the loading of the image and boot.oat.
//
// 1. The image is expected to be loaded at an absolute address and
// contains Objects with absolute pointers within the image.
//
// 2. There are absolute pointers from Methods in the image to their
// code in the oat.
//
// 3. There are absolute pointers from the code in the oat to Methods
// in the image.
//
// 4. There are absolute pointers from code in the oat to other code
// in the oat.
//
// To get this all correct, we go through several steps.
//
// 1. We have already created that oat file above with
// CreateOatFile. Originally this was just our own proprietary file
// but now it is contained within an ELF dynamic object (aka an .so
// file). The Compiler returned by CreateOatFile provides
// PatchInformation for references to oat code and Methods that need
// to be update once we know where the oat file will be located
// after the image.
//
// 2. We create the image file. It needs to know where the oat file
// will be loaded after itself. Originally when oat file was simply
// memory mapped so we could predict where its contents were based
// on the file size. Now that it is an ELF file, we need to inspect
// the ELF file to understand the in memory segment layout including
// where the oat header is located within. ImageWriter's
// PatchOatCodeAndMethods uses the PatchInformation from the
// Compiler to touch up absolute references in the oat file.
//
// 3. We fixup the ELF program headers so that dlopen will try to
// load the .so at the desired location at runtime by offsetting the
// Elf32_Phdr.p_vaddr values by the desired base address.
//
if (image) {
timings.NewSplit("dex2oat ImageWriter");
//创建image
bool image_creation_success = dex2oat->CreateImageFile(image_filename,
image_base,
oat_unstripped,
oat_location,
*compiler.get());
if (!image_creation_success) {
return EXIT_FAILURE;
}
VLOG(compiler) << "Image written successfully: " << image_filename;
}
if (is_host) {
if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
if (dump_passes) {
LOG(INFO) << Dumpable<CumulativeLogger>(*compiler.get()->GetTimingsLogger());
}
return EXIT_SUCCESS;
}
// If we don't want to strip in place, copy from unstripped location to stripped location.
// We need to strip after image creation because FixupElf needs to use .strtab.
if (oat_unstripped != oat_stripped) {
timings.NewSplit("dex2oat OatFile copy");
oat_file.reset();
std::unique_ptr<File> in(OS::OpenFileForReading(oat_unstripped.c_str()));
std::unique_ptr<File> out(OS::CreateEmptyFile(oat_stripped.c_str()));
size_t buffer_size = 8192;
std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_size]);
while (true) {
int bytes_read = TEMP_FAILURE_RETRY(read(in->Fd(), buffer.get(), buffer_size));
if (bytes_read <= 0) {
break;
}
bool write_ok = out->WriteFully(buffer.get(), bytes_read);
CHECK(write_ok);
}
oat_file.reset(out.release());
VLOG(compiler) << "Oat file copied successfully (stripped): " << oat_stripped;
// 创建oat文件
std::unique_ptr<File> oat_file;
bool create_file = !oat_unstripped.empty(); // as opposed to using open file descriptor
if (create_file) {
oat_file.reset(OS::CreateEmptyFile(oat_unstripped.c_str()));
if (oat_location.empty()) {
oat_location = oat_filename;
}
} else {
oat_file.reset(new File(oat_fd, oat_location));
oat_file->DisableAutoClose();
}
if (oat_file.get() == nullptr) {
PLOG(ERROR) << "Failed to create oat file: " << oat_location;
return EXIT_FAILURE;
}
if (create_file && fchmod(oat_file->Fd(), 0644) != 0) {
PLOG(ERROR) << "Failed to make oat file world readable: " << oat_location;
return EXIT_FAILURE;
}
timings.StartSplit("dex2oat Setup");
LOG(INFO) << CommandLine();
Runtime::Options runtime_options;
std::vector<const DexFile*> boot_class_path;
if (boot_image_option.empty()) {
size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
if (failure_count > 0) {
LOG(ERROR) << "Failed to open some dex files: " << failure_count;
return EXIT_FAILURE;
}
runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
} else {
runtime_options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
}
for (size_t i = 0; i < runtime_args.size(); i++) {
runtime_options.push_back(std::make_pair(runtime_args[i], nullptr));
}
VerificationResults verification_results(&compiler_options);
DexFileToMethodInlinerMap method_inliner_map;
CompilerCallbacksImpl callbacks(&verification_results, &method_inliner_map);
runtime_options.push_back(std::make_pair("compilercallbacks", &callbacks));
runtime_options.push_back(
std::make_pair("imageinstructionset",
reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
Dex2Oat* p_dex2oat;
if (!Dex2Oat::Create(&p_dex2oat,
runtime_options,
compiler_options,
compiler_kind,
instruction_set,
instruction_set_features,
&verification_results,
&method_inliner_map,
thread_count)) {
LOG(ERROR) << "Failed to create dex2oat";
return EXIT_FAILURE;
}
std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);
// TODO: Not sure whether it's a good idea to allow anything else but the runtime option in
// this case at all, as we'll have to throw away produced code for a mismatch.
// 参数判断
if (!has_explicit_checks_options) {
if (instruction_set == kRuntimeISA) {
Runtime* runtime = Runtime::Current();
compiler_options.SetExplicitNullChecks(runtime->ExplicitNullChecks());
compiler_options.SetExplicitStackOverflowChecks(runtime->ExplicitStackOverflowChecks());
compiler_options.SetExplicitSuspendChecks(runtime->ExplicitSuspendChecks());
}
}
// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now so that we don't starve GC.
// 线程悬挂,因此不触发GC
Thread* self = Thread::Current();
self->TransitionFromRunnableToSuspended(kNative);
// If we're doing the image, override the compiler filter to force full compilation. Must be
// done ahead of WellKnownClasses::Init that causes verification. Note: doesn't force
// compilation of class initializers.
// Whilst we're in native take the opportunity to initialize well known classes.
// init 常用类
WellKnownClasses::Init(self->GetJniEnv());
// If --image-classes was specified, calculate the full list of classes to include in the image
// 编译目标
std::unique_ptr<CompilerDriver::DescriptorSet> image_classes(nullptr);
if (image_classes_filename != nullptr) {
std::string error_msg;
if (image_classes_zip_filename != nullptr) {
image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
image_classes_filename,
&error_msg));
} else {
//如果classes filename不为空
//将class文件编译进image
image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
}
if (image_classes.get() == nullptr) {
LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename <<
"': " << error_msg;
return EXIT_FAILURE;
}
} else if (image) {
image_classes.reset(new CompilerDriver::DescriptorSet);
}
std::vector<const DexFile*> dex_files;
if (boot_image_option.empty()) {
dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath();
} else {
// image初始化的option
// 读取dexfile
if (dex_filenames.empty()) {
ATRACE_BEGIN("Opening zip archive from file descriptor");
std::string error_msg;
std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(),
&error_msg));
if (zip_archive.get() == nullptr) {
LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': "
<< error_msg;
return EXIT_FAILURE;
}
const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location, &error_msg);
if (dex_file == nullptr) {
LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
<< "': " << error_msg;
return EXIT_FAILURE;
}
dex_files.push_back(dex_file);
ATRACE_END();
} else {
size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files);
if (failure_count > 0) {
LOG(ERROR) << "Failed to open some dex files: " << failure_count;
return EXIT_FAILURE;
}
}
//dex file保存
const bool kSaveDexInput = false;
if (kSaveDexInput) {
for (size_t i = 0; i < dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i));
std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
if (tmp_file.get() == nullptr) {
PLOG(ERROR) << "Failed to open file " << tmp_file_name
<< ". Try: adb shell chmod 777 /data/local/tmp";
continue;
}
tmp_file->WriteFully(dex_file->Begin(), dex_file->Size());
LOG(INFO) << "Wrote input to " << tmp_file_name;
}
}
}
// Ensure opened dex files are writable for dex-to-dex transformations.
for (const auto& dex_file : dex_files) {
if (!dex_file->EnableWrite()) {
PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
}
}
/*
* If we're not in interpret-only or verify-none mode, go ahead and compile small applications.
* Don't bother to check if we're doing the image.
*/
if (!image && compiler_options.IsCompilationEnabled()) {
size_t num_methods = 0;
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
num_methods += dex_file->NumMethodIds();
}
//如果dex中方法少的话,编译选项改为speed
if (num_methods <= compiler_options.GetNumDexMethodsThreshold()) {
compiler_options.SetCompilerFilter(CompilerOptions::kSpeed);
VLOG(compiler) << "Below method threshold, compiling anyways";
}
}
//创建oat文件
std::unique_ptr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
android_root,
is_host,
dex_files,
oat_file.get(),
bitcode_filename,
image,
image_classes,
dump_stats,
dump_passes,
timings,
compiler_phases_timings,
profile_file));
if (compiler.get() == nullptr) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
return EXIT_FAILURE;
}
VLOG(compiler) << "Oat file written successfully (unstripped): " << oat_location;
// Notes on the interleaving of creating the image and oat file to
// ensure the references between the two are correct.
//
// Currently we have a memory layout that looks something like this:
//
// +--------------+
// | image |
// +--------------+
// | boot oat |
// +--------------+
// | alloc spaces |
// +--------------+
//
// There are several constraints on the loading of the image and boot.oat.
//
// 1. The image is expected to be loaded at an absolute address and
// contains Objects with absolute pointers within the image.
//
// 2. There are absolute pointers from Methods in the image to their
// code in the oat.
//
// 3. There are absolute pointers from the code in the oat to Methods
// in the image.
//
// 4. There are absolute pointers from code in the oat to other code
// in the oat.
//
// To get this all correct, we go through several steps.
//
// 1. We have already created that oat file above with
// CreateOatFile. Originally this was just our own proprietary file
// but now it is contained within an ELF dynamic object (aka an .so
// file). The Compiler returned by CreateOatFile provides
// PatchInformation for references to oat code and Methods that need
// to be update once we know where the oat file will be located
// after the image.
//
// 2. We create the image file. It needs to know where the oat file
// will be loaded after itself. Originally when oat file was simply
// memory mapped so we could predict where its contents were based
// on the file size. Now that it is an ELF file, we need to inspect
// the ELF file to understand the in memory segment layout including
// where the oat header is located within. ImageWriter's
// PatchOatCodeAndMethods uses the PatchInformation from the
// Compiler to touch up absolute references in the oat file.
//
// 3. We fixup the ELF program headers so that dlopen will try to
// load the .so at the desired location at runtime by offsetting the
// Elf32_Phdr.p_vaddr values by the desired base address.
//
if (image) {
timings.NewSplit("dex2oat ImageWriter");
//创建image
bool image_creation_success = dex2oat->CreateImageFile(image_filename,
image_base,
oat_unstripped,
oat_location,
*compiler.get());
if (!image_creation_success) {
return EXIT_FAILURE;
}
VLOG(compiler) << "Image written successfully: " << image_filename;
}
if (is_host) {
if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
LOG(INFO) << Dumpable<TimingLogger>(timings);
}
if (dump_passes) {
LOG(INFO) << Dumpable<CumulativeLogger>(*compiler.get()->GetTimingsLogger());
}
return EXIT_SUCCESS;
}
// If we don't want to strip in place, copy from unstripped location to stripped location.
// We need to strip after image creation because FixupElf needs to use .strtab.
if (oat_unstripped != oat_stripped) {
timings.NewSplit("dex2oat OatFile copy");
oat_file.reset();
std::unique_ptr<File> in(OS::OpenFileForReading(oat_unstripped.c_str()));
std::unique_ptr<File> out(OS::CreateEmptyFile(oat_stripped.c_str()));
size_t buffer_size = 8192;
std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_size]);
while (true) {
int bytes_read = TEMP_FAILURE_RETRY(read(in->Fd(), buffer.get(), buffer_size));
if (bytes_read <= 0) {
break;
}
bool write_ok = out->WriteFully(buffer.get(), bytes_read);
CHECK(write_ok);
}
oat_file.reset(out.release());
VLOG(compiler) << "Oat file copied successfully (stripped): " << oat_stripped;