art虚拟机缓存文件创建patchoat进程的分析

patchoat进程是Android系统中用于创建和更新ART缓存文件的关键步骤。当zygote启动时,若缓存文件不存在,patchoat进程会被fork出来,解析参数并生成位于/data/dalvik-cache的系统框架缓存。该过程涉及多个步骤,包括patchoat.main、patchoat.patchoat、Runtime创建、Heap创建、ImageSpace初始化等,通过对boot.art和boot.oat的重定位,生成最终的缓存文件。整个过程完成后,patchoat进程结束,zygote进程继续执行。
摘要由CSDN通过智能技术生成

标签(空格分隔): 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值