标签(空格分隔): javaVM patchoat art android5.1
patchoat进程是由zygote进程第一次启动时,如果在/data/dalvik-cache/x86/下没有jvm的一些缓存文件,则会fork出一个子进程,来进行这些文件的创建,同时其父进程zygote会处于等待状态,直至patchoat进程工作完成,进程patchoat的启动是通过fork和execv系统调用产生的,其启动参数为,我这里为x86的架构。
/system/bin/patchoat
–input-image-location=/system/framework/boot.art
–output-image-file=/data/dalvik-cache/x86/system@framework@boot.art
–input-oat-location=/system/framework/boot.oat
–output-oat-file=/data/dalvik-cache/x86/system@framework@boot.oat
–instruction-set=x86
–base-offset-delta=-344064
在分析之前,先贴上本文的时序图,提前有一个宏观上的了解。
下面结合源码详细分析每一个过程。
Step1: patchoat.main (/art/patchoat/patchoat.cc)
这个方法实现很简单,就是继续调用namespace art下的patchoat函数
Step2: patchoat.patchoat (/art/patchoat/patchoat.cc)
static int patchoat(int argc, char **argv) {
InitLogging(argv);
MemMap::Init();
...
for (int i = 0; i < argc; i++) {
...
}
...
bool ret;
if (have_image_files && have_oat_files) {
TimingLogger::ScopedTiming pt("patch image and oat", &timings);
ret = PatchOat::Patch(input_oat.get(), input_image_location, base_delta,
output_oat.get(), output_image.get(), isa, &timings,
output_oat_fd >= 0, // was it opened from FD?
new_oat_out);
// The order here doesn't matter. If the first one is successfully saved and the second one
// erased, ImageSpace will still detect a problem and not use the files.
ret = ret && FinishFile(output_image.get(), ret);
ret = ret && FinishFile(output_oat.get(), ret);
} else if (have_oat_files) {
TimingLogger::ScopedTiming pt("patch oat", &timings);
ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings,
output_oat_fd >= 0, // was it opened from FD?
new_oat_out);
ret = ret && FinishFile(output_oat.get(), ret);
} else if (have_image_files) {
TimingLogger::ScopedTiming pt("patch image", &timings);
ret = PatchOat::Patch(input_image_location, base_delta, output_image.get(), isa, &timings);
ret = ret && FinishFile(output_image.get(), ret);
} else {
CHECK(false);
ret = true;
}
if (kIsDebugBuild) {
LOG(INFO) << "Exiting with return ... " << ret;
}
cleanup(ret);
return (ret) ? EXIT_SUCCESS : EXIT_FAILURE;
}
在这个方法中,首先for循环中解析execv系统调用的argv参数,have_image_files和have_oat_files均为true,在我们这种情况下,由于系统第一次运行/data/dalvik-cache/x86目录下为空,从命令行解析参数执行效果来看,会在/data/dalvik-cache/x86目录下创建system@framework@boot.art和system@framework@boot.oat文件,用来最后将重定向后的缓存文件生成到此处,接下来去调用函数PatchOat::Patch去执行下一步。
Step3: PatchOat::Patch (/art/patchoat/patchoat.cc)
bool PatchOat::Patch(File* input_oat, const std::string& image_location, off_t delta,
File* output_oat, File* output_image, InstructionSet isa,
TimingLogger* timings,
bool output_oat_opened_from_fd,
bool new_oat_out) {
...
const char* isa_name = GetInstructionSetString(isa);
std::string image_filename;
if (!LocationToFilename(image_location, isa, &image_filename)) {
LOG(ERROR) << "Unable to find image at location " << image_location;
return false;
}
std::unique_ptr<File> input_image(OS::OpenFileForReading(image_filename.c_str()));
if (input_image.get() == nullptr) {
LOG(ERROR) << "unable to open input image file at " << image_filename
<< " for location " << image_location;
return false;
}
int64_t image_len = input_image->GetLength();
if (image_len < 0) {
LOG(ERROR) << "Error while getting image length";
return false;
}
ImageHeader image_header;
if (sizeof(image_header) != input_image->Read(reinterpret_cast<char*>(&image_header),
sizeof(image_header), 0)) {
LOG(ERROR) << "Unable to read image header from image file " << input_image->GetPath();
}
/*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath());
// Nothing special to do right now since the image always needs to get patched.
// Perhaps in some far-off future we may have images with relative addresses that are true-PIC.
// Set up the runtime
RuntimeOptions options;
NoopCompilerCallbacks callbacks;
options.push_back(std::make_pair("compilercallbacks", &callbacks));
std::string img = "-Ximage:" + image_location;
options.push_back(std::make_pair(img.c_str(), nullptr));
options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name)));
if (!Runtime::Create(options, false)) {
LOG(ERROR) << "Unable to initialize runtime";
return false;
}
// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now and then switch to a more manageable ScopedObjectAccess.
Thread::Current()->TransitionFromRunnableToSuspended(kNative);
ScopedObjectAccess soa(Thread::Current());
t.NewTiming("Image and oat Patching setup");
// Create the map where we will write the image patches to.
std::string error_msg;
std::unique_ptr<MemMap> image(MemMap::MapFile(image_len, PROT_READ | PROT_WRITE, MAP_PRIVATE,
input_image->Fd(), 0,
input_image->GetPath().c_str(),
&error_msg));
if (image.get() == nullptr) {
LOG(ERROR) << "unable to map image file " << input_image->GetPath() << " : " << error_msg;
return false;
}
gc::space::ImageSpace* ispc = Runtime::Current()->GetHeap()->GetImageSpace();
std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat,
PROT_READ | PROT_WRITE, MAP_PRIVATE, &am