Introduction to the

In Android system 5.0 and above, Dalvik VIRTUAL machine is gradually discarded. ART virtual machine is mainly promoted in all Android systems 5.0 and above, due to the algorithm optimization of memory allocation and recycling of ART virtual machine, which reduces the degree of memory fragmentation and reduces the recycling time. In ART virtual machine, ART will compile Dex through dex2OAT tool to get an ELF file, which is an executable file. So let’s analyze the dex2OAT realization of ART.

Dex2oat introduction

Dex2oat stands for Dalvik Excutable File to Optimized Art File. It is a program for compiling and optimizing dex files in the Android system. Dex2oat compilation and optimization can greatly improve the startup speed of Android system and the smoothness of the process of using mobile phones.

Dex2oat is stored in/ system/bin/ dex2OAT in the Android environment

The path of dex2OAT in open source system is \art\ dex2Oat \ dex2Oat.cc.

Why use Dex2OAT for conversion

In the Android system, The Dex file can be recognized by The Android VIRTUAL machine. If the App loads the DEX file into the memory every time and interprets the bytecode, the efficiency will be very low, thus affecting the user’s experience in using the Android phone. By using Dex2OAT for optimization processing, the dex file bytecode can be converted into the machine code that can be executed on the virtual machine in advance at an appropriate time before the android system runs, and then run directly from the machine code with higher efficiency, so that the running stage will be smoother and user experience will be optimized.

Dex2oat code

Dex2oat class definition

class Dex2Oat {
 public:
 
 // create a function that returns bool,
  static bool Create(Dex2Oat** p_dex2oat,
                     const RuntimeOptions& runtime_options,
                     const CompilerOptions& compiler_options,
                     Compiler::Kind compiler_kind,
                     InstructionSet instruction_set,
                     InstructionSetFeatures instruction_set_features,
                     VerificationResults* verification_results,
                     DexFileToMethodInlinerMap* method_inliner_map,
                     size_t thread_count)
      SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
      // Determine that the release passed in is null
    CHECK(verification_results ! =nullptr);
    CHECK(method_inliner_map ! =nullptr);
    // Use smart pointer to de-instantiate dex2OAT
    std::unique_ptr<Dex2Oat> dex2oat(new Dex2Oat(&compiler_options,
                                           compiler_kind,
                                           instruction_set,
                                           instruction_set_features,
                                           verification_results,
                                           method_inliner_map,
                                           thread_count));
    if(! dex2oat->CreateRuntime(runtime_options, instruction_set)) {
      *p_dex2oat = nullptr;
      return false;
    }
    *p_dex2oat = dex2oat.release(a);return true;
  }
    // a dummy function of dex2OAT for the release operation.
  ~Dex2Oat() {
    delete runtime_;
    LogCompletionTime(a); }void LogCompletionTime(a) {
    LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_)
              << " (threads: " << thread_count_ << ")";
  }


  
  // Get the class name from the file
  std::set<std::string>* ReadImageClassesFromFile(const char* image_classes_filename) {
    std::unique_ptr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename,
                                                                  std::ifstream::in));
    if (image_classes_file.get() = =nullptr) {
      LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
      return nullptr;
    }
    std::unique_ptr<std::set<std::string>> result(ReadImageClasses(*image_classes_file));
    image_classes_file->close(a);return result.release(a); }/ / read imageclasses
  std::set<std::string>* ReadImageClasses(std::istream& image_classes_stream) {
    std::unique_ptr<std::set<std::string>> image_classes(new std::set<std::string>);
    while (image_classes_stream.good()) {
      std::string dot;
      std::getline(image_classes_stream, dot);
      if (StartsWith(dot, "#") || dot.empty()) {
        continue;
      }
      std::string descriptor(DotToDescriptor(dot.c_str()));
      image_classes->insert(descriptor);
    }
    return image_classes.release(a); }// Reads the class names (java.lang.Object) and returns a set of descriptors (Ljava/lang/Object;)
  // Read the class name from the zip file (apk is a zip file) and return a description
  std::set<std::string>* ReadImageClassesFromZip(const char* zip_filename,
                                                         const char* image_classes_filename,
                                                         std::string* error_msg) {
         // Use smart pointer to open zip package, also known as APK package
    std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename, error_msg));
    // Check whether opening failed
    if (zip_archive.get() = =nullptr) {
      return nullptr;
    }
    // Traverse the zip package to obtain the file information in the zip package
    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
    if (zip_entry.get() = =nullptr) {
      *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
                                zip_filename, error_msg->c_str());
      return nullptr;
    }
    std::unique_ptr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(zip_filename, image_classes_filename, error_msg));
    if (image_classes_file.get() = =nullptr) {
      *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", image_classes_filename,
                                zip_filename, error_msg->c_str());
      return nullptr;
    }
    const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
                                           image_classes_file->Size());
    std::istringstream image_classes_stream(image_classes_string);
    return ReadImageClasses(image_classes_stream);
  }

  bool PatchOatCode(const CompilerDriver* compiler_driver, File* oat_file,
                    const std::string& oat_location, std::string* error_msg) {
    // We asked to include patch information but we are not making an image. We need to fix
    // everything up manually.
    std::unique_ptr<ElfFile> elf_file(ElfFile::Open(oat_file, PROT_READ|PROT_WRITE, MAP_SHARED, error_msg));
    if (elf_file.get() = =NULL) {
      LOG(ERROR) << error_msg;
      return false;
    }
    {
      ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_);
      return ElfPatcher::Patch(compiler_driver, elf_file.get(), oat_location, error_msg); }}// Create an OAT file that returns a constant pointer
  const CompilerDriver* CreateOatFile(const std::string& boot_image_option,
                                      const std::string& android_root,
                                      bool is_host,
                                      const std::vector<const DexFile*>& dex_files,
                                      File* oat_file,
                                      const std::string& oat_location,
                                      const std::string& bitcode_filename,
                                      bool image,
                                      std::unique_ptr<std::set<std::string>>& image_classes,
                                      bool dump_stats,
                                      bool dump_passes,
                                      TimingLogger& timings,
                                      CumulativeLogger& compiler_phases_timings,
                                      std::string profile_file,
                                      SafeMap<std::string, std::string>* key_value_store) {
    CHECK(key_value_store ! =nullptr);

    // Handle and ClassLoader creation needs to come after Runtime::Create
    jobject class_loader = nullptr;
    // Get its own process
    Thread* self = Thread::Current(a);// If boot_image_option is not empty, execute the following code
    if(! boot_image_option.empty()) {
    
      ClassLinker* class_linker = Runtime::Current() - >GetClassLinker(a);std::vector<const DexFile*> class_path_files(dex_files);
      OpenClassPathFiles(runtime_->GetClassPathString(), class_path_files);
      ScopedObjectAccess soa(self);
      // Loop through and class file size, and register the dex file
      for (size_t i = 0; i < class_path_files.size(a); i++) { class_linker->RegisterDexFile(*class_path_files[i]);
      }
      soa.Env() - >AllocObject(WellKnownClasses::dalvik_system_PathClassLoader);
      ScopedLocalRef<jobject> class_loader_local(soa.Env(), soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
      class_loader = soa.Env() - >NewGlobalRef(class_loader_local.get());
      
      Runtime::Current() - >SetCompileTimeClassPath(class_loader, class_path_files);
    }


    std::unique_ptr<CompilerDriver> driver(new CompilerDriver(compiler_options_,
                                                              verification_results_,
                                                              method_inliner_map_,
                                                              compiler_kind_,
                                                              instruction_set_,
                                                              instruction_set_features_,
                                                              image,
                                                              image_classes.release(),
                                                              thread_count_,
                                                              dump_stats,
                                                              dump_passes,
                                                              &compiler_phases_timings,
                                                              profile_file));

    driver->GetCompiler() - >SetBitcodeFileName(*driver.get(), bitcode_filename);

    driver->CompileAll(class_loader, dex_files, &timings);

    TimingLogger::ScopedTiming t2("dex2oat OatWriter", &timings);
    std::string image_file_location;
    uint32_t image_file_location_oat_checksum = 0;
    uintptr_t image_file_location_oat_data_begin = 0;
    int32_t image_patch_delta = 0;
    if(! driver->IsImage()) {
      TimingLogger::ScopedTiming t3("Loading image checksum", &timings);
      gc::space::ImageSpace* image_space = Runtime::Current() - >GetHeap() - >GetImageSpace(a); image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum(a); image_file_location_oat_data_begin =reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin());
      image_file_location = image_space->GetImageFilename(a); image_patch_delta = image_space->GetImageHeader().GetPatchDelta(a); }if(! image_file_location.empty()) {
      key_value_store->Put(OatHeader::kImageLocationKey, image_file_location);
    }

    // oAT write operation
    OatWriter oat_writer(dex_files, image_file_location_oat_checksum, image_file_location_oat_data_begin, image_patch_delta, driver.get(), &timings, key_value_store);

    t2.NewTiming("Writing ELF");
    if(! driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
      LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath(a);return nullptr;
    }

    // Flush result to disk. Patching code will re-open the file (mmap), so ensure that our view
    // of the file already made it there and won't be re-ordered with writes from PatchOat or
    // image patching.
    oat_file->Flush(a);if(! driver->IsImage() && driver->GetCompilerOptions().GetIncludePatchInformation()) {
      t2.NewTiming("Patching ELF");
      std::string error_msg;
      if (!PatchOatCode(driver.get(), oat_file, oat_location, &error_msg)) {
        LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath() < <":" << error_msg;
        return nullptr; }}return driver.release(a); }// Create a mapping file, return true on success, false on failure
  bool CreateImageFile(const std::string& image_filename,
                       uintptr_t image_base,
                       const std::string& oat_filename,
                       const std::string& oat_location,
                       const CompilerDriver& compiler)
      LOCKS_EXCLUDED(Locks::mutator_lock_) {
    uintptr_t oat_data_begin;
    {
      // ImageWriter is scoped so it can free memory before doing FixupElf
      ImageWriter image_writer(compiler);
      if(! image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
        LOG(ERROR) << "Failed to create image file " << image_filename;
        return false;
      }
      oat_data_begin = image_writer.GetOatDataBegin(a); }std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename.c_str()));
    if (oat_file.get() = =nullptr) {
      PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
      return false;
    }
    if(! ElfFixup::Fixup(oat_file.get(), oat_data_begin)) {
      LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath(a);return false;
    }
    return true;
  }

 private:
 // Define a display dex2OAT constructor
  explicit Dex2Oat(const CompilerOptions* compiler_options,
                   Compiler::Kind compiler_kind,
                   InstructionSet instruction_set,
                   InstructionSetFeatures instruction_set_features,
                   VerificationResults* verification_results,
                   DexFileToMethodInlinerMap* method_inliner_map,
                   size_t thread_count)
      : compiler_options_(compiler_options),
        compiler_kind_(compiler_kind),
        instruction_set_(instruction_set),
        instruction_set_features_(instruction_set_features),
        verification_results_(verification_results),
        method_inliner_map_(method_inliner_map),
        runtime_(nullptr),
        thread_count_(thread_count),
        start_ns_(NanoTime()) {
    CHECK(compiler_options ! =nullptr);
    CHECK(verification_results ! =nullptr);
    CHECK(method_inliner_map ! =nullptr);
  }

  bool CreateRuntime(const RuntimeOptions& runtime_options, InstructionSet instruction_set)
      SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
    if(! Runtime::Create(runtime_options, false)) {
      LOG(ERROR) << "Failed to create runtime";
      return false;
    }
    Runtime* runtime = Runtime::Current(a); runtime->SetInstructionSet(instruction_set);
    for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
      Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
      if(! runtime->HasCalleeSaveMethod(type)) {
        runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(type), type);
      }
    }
    runtime->GetClassLinker() - >FixupDexCaches(runtime->GetResolutionMethod());
    runtime->GetClassLinker() - >RunRootClinits(a); runtime_ = runtime;return true;
  }

  // Appends to dex_files any elements of class_path that it doesn't already
  // contain. This will open those dex files as necessary.
  static void OpenClassPathFiles(const std::string& class_path,
                                 std::vector<const DexFile*>& dex_files) {
   // By defining the string of l vectors
   std::vector<std::string> parsed;
    Split(class_path, ':', parsed);
    // Take Locks::mutator_lock_ so that lock ordering on the ClassLinker::dex_lock_ is maintained.
    ScopedObjectAccess soa(Thread::Current());
    for (size_t i = 0; i < parsed.size(a); ++i) {// Check whether the dex file is included
      if (DexFilesContains(dex_files, parsed[i])) {
        continue;
      }
      std::string error_msg;
      // Check whether the dex file can be opened
      if(! DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg, &dex_files)) {
        LOG(WARNING) << "Failed to open dex file '" << parsed[i] << "'."<< error_msg; }}}// Return true if the dex file has a specified location
  static bool DexFilesContains(const std::vector<const DexFile*>& dex_files,
                               const std::string& location) {
    // Loop over the size of the dex file and determine if location is equal.
   for (size_t i = 0; i < dex_files.size(a); ++i) {if (dex_files[i]->GetLocation() == location) {
        return true; }}return false;
  }
    
   // Define four constants
  const CompilerOptions* const compiler_options_;
  const Compiler::Kind compiler_kind_;

  const InstructionSet instruction_set_;
  const InstructionSetFeatures instruction_set_features_;

  VerificationResults* const verification_results_;
  DexFileToMethodInlinerMap* const method_inliner_map_;
  Runtime* runtime_;
  size_t thread_count_;
  uint64_t start_ns_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
};
Copy the code

OpenDexFiles function definition

//OpenDexFiles Opens the dex file and returns the size of the dex file successfully
static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames,
                           const std::vector<const char*>& dex_locations,
                           std::vector<const DexFile*>& dex_files) {
  size_t failure_count = 0;
  // Loop over the size of the dex file.
  for (size_t i = 0; i < dex_filenames.size(); i++) {
    const char* dex_filename = dex_filenames[i];
    const char* dex_location = dex_locations[i];
    ATRACE_BEGIN(StringPrintf("Opening dex file '%s'", dex_filenames[i]).c_str());
    std::string error_msg;
    // Check whether the file exists.
    if(! OS::FileExists(dex_filename)) { LOG(WARNING) <<"Skipping non-existent dex file '" << dex_filename << "'";
      continue;
    }
    // The actual open operation is achieved by calling the underlying open function.
    if(! DexFile::Open(dex_filename, dex_location, &error_msg, &dex_files)) { LOG(WARNING) <<"Failed to open .dex from file '" << dex_filename << "'." << error_msg;
      ++failure_count;
    }
    ATRACE_END();
  }
  return failure_count;
}
Copy the code

Dex2oat entry function definition

Below is the whole flow of the Dex2OAT function

  1. Do a workaround on arm.
  2. Construct a Dex2oat object
  3. Process command line arguments
  4. Check whether the file has the write permission
  5. Prints command line arguments
  6. Determine if setup of dex2OAT is complete
  7. Call CompileImage or CompileApp depending on whether image is generated
// Dex2OAT parameters are input through the control window
static int dex2oat(int argc, char** argv) {
#if defined(__linux__) && defined(__arm__)
  // Define variables
  int major, minor;
  // Define a structure to get host information
  struct utsname uts;
  // Call uname to check whether system information can be displayed
  if (uname(&uts) ! =- 1 &&
      sscanf(uts.release, "%d.%d", &major, &minor) == 2 &&
      ((major < 3) || ((major == 3) && (minor < 4)))) {
    Don't handle the ASLR well and we can run out of address
    // space (http://b/13564922). Work around the issue by inhibiting further mmap() randomization.
    int old_personality = personality(0xffffffff);
    if ((old_personality & ADDR_NO_RANDOMIZE) == 0) {
      int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
      if (new_personality == - 1) {
        LOG(WARNING) << "personality(. | ADDR_NO_RANDOMIZE) failed."; }}}#endif
    // Arguments pass assignments to global variables
  original_argc = argc;
  original_argv = argv;
   // Prints the program execution time
  TimingLogger timings("compiler".false.false);
  CumulativeLogger compiler_phases_timings("compilation times");

  InitLogging(argv);

  // Skip over argv[0].
  argv++;
  argc--;

  if (argc == 0) {
    Usage("No arguments specified");
  }
  // Up to now, we have done the initialization and environment operation. The real dex2OAT function is implemented in the following code.

// Define a series of vectors, strings, and constants for use in the following code
  std::vector<const char*> dex_filenames;
  std::vector<const char*> dex_locations;
  int zip_fd = - 1;
  std::string zip_location;
  std::string oat_filename;
  std::string oat_symbols;
  std::string oat_location;
  int oat_fd = - 1;
  std::string bitcode_filename;
  const char* image_classes_zip_filename = nullptr;
  const char* image_classes_filename = nullptr;
  std::string image_filename;
  std::string boot_image_filename;
  uintptr_t image_base = 0;
  std::string android_root;
  std::vector<const char*> runtime_args;
  int thread_count = sysconf(_SC_NPROCESSORS_CONF);
  Compiler::Kind compiler_kind = kUsePortableCompiler
      ? Compiler::kPortable
      : Compiler::kQuick;
  const char* compiler_filter_string = nullptr;
  int huge_method_threshold = CompilerOptions::kDefaultHugeMethodThreshold;
  int large_method_threshold = CompilerOptions::kDefaultLargeMethodThreshold;
  int small_method_threshold = CompilerOptions::kDefaultSmallMethodThreshold;
  int tiny_method_threshold = CompilerOptions::kDefaultTinyMethodThreshold;
  int num_dex_methods_threshold = CompilerOptions::kDefaultNumDexMethodsThreshold;
  

  // Get the default directive function set from the build.
  InstructionSetFeatures instruction_set_features =
      ParseFeatureList(Runtime::GetDefaultInstructionSetFeatures());

  InstructionSet instruction_set = kRuntimeISA;

  // The configuration file definition is used
  std::string profile_file;
  double top_k_profile_threshold = CompilerOptions::kDefaultTopKProfileThreshold;

  bool is_host = false;
  bool dump_stats = false;
  bool dump_timing = false;
  bool dump_passes = false;
  bool include_patch_information = CompilerOptions::kDefaultIncludePatchInformation;
  bool include_debug_symbols = kIsDebugBuild;
  bool dump_slow_timing = kIsDebugBuild;
  bool watch_dog_enabled = true;
  bool generate_gdb_information = kIsDebugBuild;

  // Checks are all explicit until we know the architecture.
  bool implicit_null_checks = false;
  bool implicit_so_checks = false;
  bool implicit_suspend_checks = false;
 
 // The main code below performs print command line operations through a series of steps.
// Count the sum of the parameters entered by the user
  for (int i = 0; i < argc; i++) {
    const StringPiece option(argv[i]);
    const bool log_options = false;
    if (log_options) {
      LOG(INFO) << "dex2oat: option[" << i << "] =" << argv[i];
    }
    // Determine if the string contains
    if (option.starts_with("--dex-file=")) {
       // Pass the dex file name into the vector
      dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
    } else if (option.starts_with("--dex-location=")) {
      dex_locations.push_back(option.substr(strlen("--dex-location=")).data());
      
    }
    // Check whether it is a ZIP file, operate on the zip file, and intercept the string information
    else if (option.starts_with("--zip-fd=")) {
      const char* zip_fd_str = option.substr(strlen("--zip-fd=")).data(a);if (!ParseInt(zip_fd_str, &zip_fd)) {
        Usage("Failed to parse --zip-fd argument '%s' as an integer", zip_fd_str);
      }
      if (zip_fd < 0) {
        Usage("--zip-fd passed a negative value %d", zip_fd); }}else if (option.starts_with("--zip-location=")) {
      zip_location = option.substr(strlen("--zip-location=")).data(a); }else if (option.starts_with("--oat-file=")) {
      oat_filename = option.substr(strlen("--oat-file=")).data(a); }else if (option.starts_with("--oat-symbols=")) {
      oat_symbols = option.substr(strlen("--oat-symbols=")).data(a); }else if (option.starts_with("--oat-fd=")) {
      const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data(a);if (!ParseInt(oat_fd_str, &oat_fd)) {
        Usage("Failed to parse --oat-fd argument '%s' as an integer", oat_fd_str);
      }
      if (oat_fd < 0) {
        Usage("--oat-fd passed a negative value %d", oat_fd); }}else if (option == "--watch-dog") {
      watch_dog_enabled = true;
    } else if (option == "--no-watch-dog") {
      watch_dog_enabled = false;
    } else if (option == "--gen-gdb-info") {
      generate_gdb_information = true;
      // Debug symbols are needed for gdb information.
      include_debug_symbols = true;
    } else if (option == "--no-gen-gdb-info") {
      generate_gdb_information = false;
    } else if (option.starts_with("-j")) {
      const char* thread_count_str = option.substr(strlen("-j")).data(a);if (!ParseInt(thread_count_str, &thread_count)) {
        Usage("Failed to parse -j argument '%s' as an integer", thread_count_str); }}else if (option.starts_with("--oat-location=")) {
      oat_location = option.substr(strlen("--oat-location=")).data(a); }else if (option.starts_with("--bitcode=")) {
      bitcode_filename = option.substr(strlen("--bitcode=")).data(a); }else if (option.starts_with("--image=")) {
      image_filename = option.substr(strlen("--image=")).data(a); }else if (option.starts_with("--image-classes=")) {
      image_classes_filename = option.substr(strlen("--image-classes=")).data(a); }else if (option.starts_with("--image-classes-zip=")) {
      image_classes_zip_filename = option.substr(strlen("--image-classes-zip=")).data(a); }else if (option.starts_with("--base=")) {
      const char* image_base_str = option.substr(strlen("--base=")).data(a);char* end;
      image_base = strtoul(image_base_str, &end, 16);
      if(end == image_base_str || *end ! ='\ 0') {
        Usage("Failed to parse hexadecimal value for option %s", option.data()); }}else if (option.starts_with("--boot-image=")) {
      boot_image_filename = option.substr(strlen("--boot-image=")).data(a); }else if (option.starts_with("--android-root=")) {
      android_root = option.substr(strlen("--android-root=")).data(a); }else if (option.starts_with("--instruction-set=")) {
      StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data(a);if (instruction_set_str == "arm") {
        instruction_set = kThumb2;
      } else if (instruction_set_str == "arm64") {
        instruction_set = kArm64;
      } else if (instruction_set_str == "mips") {
        instruction_set = kMips;
      } else if (instruction_set_str == "x86") {
        instruction_set = kX86;
      } else if (instruction_set_str == "x86_64") { instruction_set = kX86_64; }}else if (option.starts_with("--instruction-set-features=")) {
      StringPiece str = option.substr(strlen("--instruction-set-features=")).data(a); instruction_set_features =ParseFeatureList(str.as_string());
    } else if (option.starts_with("--compiler-backend=")) {
      StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data(a);if (backend_str == "Quick") {
        compiler_kind = Compiler::kQuick;
      } else if (backend_str == "Optimizing") {
        compiler_kind = Compiler::kOptimizing;
      } else if (backend_str == "Portable") { compiler_kind = Compiler::kPortable; }}else if (option.starts_with("--compiler-filter=")) {
      compiler_filter_string = option.substr(strlen("--compiler-filter=")).data(a); }else if (option.starts_with("--huge-method-max=")) {
      const char* threshold = option.substr(strlen("--huge-method-max=")).data(a);if (!ParseInt(threshold, &huge_method_threshold)) {
        Usage("Failed to parse --huge-method-max '%s' as an integer", threshold);
      }
      if (huge_method_threshold < 0) {
        Usage("--huge-method-max passed a negative value %s", huge_method_threshold); }}else if (option.starts_with("--large-method-max=")) {
      const char* threshold = option.substr(strlen("--large-method-max=")).data(a);if (!ParseInt(threshold, &large_method_threshold)) {
        Usage("Failed to parse --large-method-max '%s' as an integer", threshold);
      }
      if (large_method_threshold < 0) {
        Usage("--large-method-max passed a negative value %s", large_method_threshold); }}else if (option.starts_with("--small-method-max=")) {
      const char* threshold = option.substr(strlen("--small-method-max=")).data(a);if (!ParseInt(threshold, &small_method_threshold)) {
        Usage("Failed to parse --small-method-max '%s' as an integer", threshold);
      }
      if (small_method_threshold < 0) {
        Usage("--small-method-max passed a negative value %s", small_method_threshold); }}else if (option.starts_with("--tiny-method-max=")) {
      const char* threshold = option.substr(strlen("--tiny-method-max=")).data(a);if (!ParseInt(threshold, &tiny_method_threshold)) {
        Usage("Failed to parse --tiny-method-max '%s' as an integer", threshold);
      }
      if (tiny_method_threshold < 0) {
        Usage("--tiny-method-max passed a negative value %s", tiny_method_threshold); }}else if (option.starts_with("--num-dex-methods=")) {
      const char* threshold = option.substr(strlen("--num-dex-methods=")).data(a);if (!ParseInt(threshold, &num_dex_methods_threshold)) {
        Usage("Failed to parse --num-dex-methods '%s' as an integer", threshold);
      }
      if (num_dex_methods_threshold < 0) {
        Usage("--num-dex-methods passed a negative value %s", num_dex_methods_threshold); }}else if (option == "--host") {
      is_host = true;
    } else if (option == "--runtime-arg") {
      if (++i >= argc) {
        Usage("Missing required argument for --runtime-arg");
      }
      if (log_options) {
        LOG(INFO) << "dex2oat: option[" << i << "] =" << argv[i];
      }
      runtime_args.push_back(argv[i]);
    } else if (option == "--dump-timing") {
      dump_timing = true;
    } else if (option == "--dump-passes") {
      dump_passes = true;
    } else if (option == "--dump-stats") {
      dump_stats = true;
    } else if (option == "--include-debug-symbols" || option == "--no-strip-symbols") {
      include_debug_symbols = true;
    } else if (option == "--no-include-debug-symbols" || option == "--strip-symbols") {
      include_debug_symbols = false;
      generate_gdb_information = false;  // Depends on debug symbols, see above.
    } else if (option.starts_with("--profile-file=")) {
      profile_file = option.substr(strlen("--profile-file=")).data(a);VLOG(compiler) << "dex2oat: profile file is " << profile_file;
    } else if (option == "--no-profile-file") {
      // No profile
    } else if (option.starts_with("--top-k-profile-threshold=")) {
      ParseDouble(option.data(), '='.0.0.100.0, &top_k_profile_threshold);
    } else if (option == "--print-pass-names") {
      PassDriverMEOpts::PrintPassNames(a); }else if (option.starts_with("--disable-passes=")) {
      std::string disable_passes = option.substr(strlen("--disable-passes=")).data(a); PassDriverMEOpts::CreateDefaultPassList(disable_passes);
    } else if (option.starts_with("--print-passes=")) {
      std::string print_passes = option.substr(strlen("--print-passes=")).data(a); PassDriverMEOpts::SetPrintPassList(print_passes);
    } else if (option == "--print-all-passes") {
      PassDriverMEOpts::SetPrintAllPasses(a); }else if (option.starts_with("--dump-cfg-passes=")) {
      std::string dump_passes = option.substr(strlen("--dump-cfg-passes=")).data(a); PassDriverMEOpts::SetDumpPassList(dump_passes);
    } else if (option == "--include-patch-information") {
      include_patch_information = true;
    } else if (option == "--no-include-patch-information") {
      include_patch_information = false;
    } else {
      Usage("Unknown argument %s", option.data()); }}// Check whether the OAT file exists
  if (oat_filename.empty() && oat_fd == - 1) {
    Usage("Output must be supplied with either --oat-file or --oat-fd");
  }

  if(! oat_filename.empty() && oat_fd ! =- 1) {
    Usage("--oat-file should not be used with --oat-fd");
  }
   // Check whether the OAT symbol table is empty
  if(! oat_symbols.empty() && oat_fd ! =- 1) {
    Usage("--oat-symbols should not be used with --oat-fd");
  }

  if(! oat_symbols.empty() && is_host) {
    Usage("--oat-symbols should not be used with --host");
  }

  if(oat_fd ! =- 1 && !image_filename.empty()) {
    Usage("--oat-fd should not be used with --image");
  }
   // Check whether android_root is empty
  if (android_root.empty()) {
    const char* android_root_env_var = getenv("ANDROID_ROOT");
    if (android_root_env_var == nullptr) {
      Usage("--android-root unspecified and ANDROID_ROOT not set");
    }
    android_root += android_root_env_var;
  }

  boolimage = (! image_filename.empty());
  if(! image && boot_image_filename.empty()) {
    boot_image_filename += android_root;
    boot_image_filename += "/framework/boot.art";
  }
  std::string boot_image_option;
  if(! boot_image_filename.empty()) {
    boot_image_option += "-Ximage:";
    boot_image_option += boot_image_filename;
  }

  if(image_classes_filename ! =nullptr && !image) {
    Usage("--image-classes should only be used with --image");
  }

  if(image_classes_filename ! =nullptr && !boot_image_option.empty()) {
    Usage("--image-classes should not be used with --boot-image");
  }

  if(image_classes_zip_filename ! =nullptr && image_classes_filename == nullptr) {
    Usage("--image-classes-zip should be used with --image-classes");
  }

  if (dex_filenames.empty() && zip_fd == - 1) {
    Usage("Input must be supplied with either --dex-file or --zip-fd");
  }

  if(! dex_filenames.empty() && zip_fd ! =- 1) {
    Usage("--dex-file should not be used with --zip-fd");
  }

  if(! dex_filenames.empty() && !zip_location.empty()) {
    Usage("--dex-file should not be used with --zip-location");
  }

  if (dex_locations.empty()) {
    for (size_t i = 0; i < dex_filenames.size(a); i++) { dex_locations.push_back(dex_filenames[i]); }}else if (dex_locations.size() != dex_filenames.size()) {
    Usage("--dex-location arguments do not match --dex-file arguments");
  }

  if(zip_fd ! =- 1 && zip_location.empty()) {
    Usage("--zip-location should be supplied with --zip-fd");
  }

  if (boot_image_option.empty()) {
    if (image_base == 0) {
      Usage("Non-zero --base not specified"); }}std::string oat_stripped(oat_filename);
  std::string oat_unstripped;
  if(! oat_symbols.empty()) {
    oat_unstripped += oat_symbols;
  } else {
    oat_unstripped += oat_filename;
  }

  if (compiler_filter_string == nullptr) {
    if (instruction_set == kMips64) {
      // TODO: fix compiler for Mips64.
      compiler_filter_string = "interpret-only";
    } else if (image) {
      compiler_filter_string = "speed";
    } else {
#if ART_SMALL_MODE
      compiler_filter_string = "interpret-only";
#else
      compiler_filter_string = "speed";
#endif}}CHECK(compiler_filter_string ! =nullptr);
  CompilerOptions::CompilerFilter compiler_filter = CompilerOptions::kDefaultCompilerFilter;
  if (strcmp(compiler_filter_string, "verify-none") = =0) {
    compiler_filter = CompilerOptions::kVerifyNone;
  } else if (strcmp(compiler_filter_string, "interpret-only") = =0) {
    compiler_filter = CompilerOptions::kInterpretOnly;
  } else if (strcmp(compiler_filter_string, "space") = =0) {
    compiler_filter = CompilerOptions::kSpace;
  } else if (strcmp(compiler_filter_string, "balanced") = =0) {
    compiler_filter = CompilerOptions::kBalanced;
  } else if (strcmp(compiler_filter_string, "speed") = =0) {
    compiler_filter = CompilerOptions::kSpeed;
  } else if (strcmp(compiler_filter_string, "everything") = =0) {
    compiler_filter = CompilerOptions::kEverything;
  } else {
    Usage("Unknown --compiler-filter value %s", compiler_filter_string);
  }

  // Set the compilation target's implicit checks options.
  switch (instruction_set) {
    case kArm:
    case kThumb2:
    case kArm64:
    case kX86:
    case kX86_64:
      implicit_null_checks = true;
      implicit_so_checks = true;
      break;

    default:
      // Defaults are correct.
      break;
  }

  std::unique_ptr<CompilerOptions> compiler_options(new CompilerOptions(compiler_filter,
                                                                        huge_method_threshold,
                                                                        large_method_threshold,
                                                                        small_method_threshold,
                                                                        tiny_method_threshold,
                                                                        num_dex_methods_threshold,
                                                                        generate_gdb_information,
                                                                        include_patch_information,
                                                                        top_k_profile_threshold,
                                                                        include_debug_symbols,
                                                                        implicit_null_checks,
                                                                        implicit_so_checks,
                                                                        implicit_suspend_checks
#ifdef ART_SEA_IR_MODE
                                                                        , compiler_options.sea_ir_ =
                                                                              true;
#endif
  ));  // NOLINT(whitespace/parens)

  // Done with usage checks, enable watchdog if requested
  WatchDog watch_dog(watch_dog_enabled);

  // Check early that the result of compilation can be written
  std::unique_ptr<File> oat_file;
  boolcreate_file = ! oat_unstripped.empty(a);// 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(a); oat_file->SetLength(0);
  }
  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;
  }
// Start to execute dex2OAT
  timings.StartTiming("dex2oat Setup");
  LOG(INFO) << CommandLine(a); RuntimeOptions runtime_options; std::vector<const DexFile*> boot_class_path;
  art::MemMap::Init(a);// For ZipEntry::ExtractToMemMap.
  if (boot_image_option.empty()) {
  // Open the dex file in zip
    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(a); i++) { runtime_options.push_back(std::make_pair(runtime_args[i], nullptr));
  }

  std::unique_ptr<VerificationResults> verification_results(new VerificationResults(
                                                            compiler_options.get()));
  DexFileToMethodInlinerMap method_inliner_map;
  QuickCompilerCallbacks callbacks(verification_results.get(), &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;
  // Create dex2OAT
  if(! Dex2Oat::Create(&p_dex2oat,
                       runtime_options,
                       *compiler_options,
                       compiler_kind,
                       instruction_set,
                       instruction_set_features,
                       verification_results.get(),
                       &method_inliner_map,
                       thread_count)) {
    LOG(ERROR) << "Failed to create dex2oat";
    return EXIT_FAILURE;
  }
  std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);

 
  Thread* self = Thread::Current(a); self->TransitionFromRunnableToSuspended(kNative);

  WellKnownClasses::Init(self->GetJniEnv());

  // If --image-classes was specified, calculate the full list of classes to include in the image
  std::unique_ptr<std::set<std::string>> 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 {
      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;
      returnEXIT_FAILURE; }}else if (image) {
    image_classes.reset(new std::set<std::string>);
  }

  std::vector<const DexFile*> dex_files;
  if (boot_image_option.empty()) {
    dex_files = Runtime::Current() - >GetClassLinker() - >GetBootClassPath(a); }else {
    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;
      }
      if(! DexFile::OpenFromZip(*zip_archive.get(), zip_location, &error_msg, &dex_files)) {
        LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
            << "'." << error_msg;
        return EXIT_FAILURE;
      }
      ATRACE_END(a); }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;
        returnEXIT_FAILURE; }}const bool kSaveDexInput = false;
    if (kSaveDexInput) {
      for (size_t i = 0; i < dex_files.size(a); ++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;
        }
        // Write to the dex file
        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(! image && compiler_options->IsCompilationEnabled()) {
    size_t num_methods = 0;
    for (size_t i = 0; i ! = dex_files.size(a); ++i) {const DexFile* dex_file = dex_files[i];
      CHECK(dex_file ! =nullptr);
      num_methods += dex_file->NumMethodIds(a); }if (num_methods <= compiler_options->GetNumDexMethodsThreshold()) {
      compiler_options->SetCompilerFilter(CompilerOptions::kSpeed);
      VLOG(compiler) << "Below method threshold, compiling anyways"; }}// Fill some values into the key-value store for the oat header.
  std::unique_ptr<SafeMap<std::string, std::string> > key_value_store(
      new SafeMap<std::string, std::string>());

  // Insert some compiler things.
  std::ostringstream oss;
  for (int i = 0; i < argc; ++i) {
    if (i > 0) {
      oss << ' ';
    }
    oss << argv[i];
  }
  key_value_store->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
  oss.str("");  // Reset.
  oss << kRuntimeISA;
  key_value_store->Put(OatHeader::kDex2OatHostKey, oss.str());

// Compile dex file function, mainly to convert dex files to oAT files
  std::unique_ptr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option, android_root, is_host, dex_files, oat_file.get(), oat_location, bitcode_filename, image, image_classes, dump_stats, dump_passes, timings, compiler_phases_timings, profile_file, key_value_store.get()));
  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;

  if (image) {
     // Prints runtime logs
    TimingLogger::ScopedTiming t("dex2oat ImageWriter", &timings);
    // Create an OAT mapping file
    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) {
    timings.EndTiming(a);if (dump_timing || (dump_slow_timing && timings.GetTotalNs(a) >MsToNs(1000))) {
      LOG(INFO) << Dumpable<TimingLogger>(timings);
    }
    if (dump_passes) {
      LOG(INFO) << Dumpable<CumulativeLogger>(*compiler.get() - >GetTimingsLogger());
    }
    return EXIT_SUCCESS;
  }

  if(oat_unstripped ! = oat_stripped) {// Record the program execution time
    TimingLogger::ScopedTiming t("dex2oat OatFile copy", &timings);
    oat_file.reset(a);// Use smart pointer to open and read files
     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;
  }

#if ART_USE_PORTABLE_COMPILER  // We currently only generate symbols on Portable
  if(! compiler_options.GetIncludeDebugSymbols()) {
    timings.NewSplit("dex2oat ElfStripper");
    // Strip unneeded sections for target
    off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
    CHECK_EQ(0, seek_actual);
    std::string error_msg;
    CHECK(ElfStripper::Strip(oat_file.get(), &error_msg)) << error_msg;


    // Successfully compiled to oAT file
    VLOG(compiler) << "Oat file written successfully (stripped): " << oat_location;
  } else {
    VLOG(compiler) << "Oat file written successfully without stripping: " << oat_location;
  }
#endif  // ART_USE_PORTABLE_COMPILER

  timings.EndTiming(a);if (dump_timing || (dump_slow_timing && timings.GetTotalNs(a) >MsToNs(1000))) {
    LOG(INFO) << Dumpable<TimingLogger>(timings);
  }
  if (dump_passes) {
    LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
  }

  if(! kIsDebugBuild && (RUNNING_ON_VALGRIND ==0)) {
    dex2oat->LogCompletionTime(a);exit(EXIT_SUCCESS);
  }

  return EXIT_SUCCESS;
}  // NOLINT(readability/fn_size)
}  // namespace art

Copy the code

conclusion

Based on the above analysis, we can specify that Dex2OAT plays a very important role in the running process of android system, because APP installation, mobile phone screen sliding, system startup and so on all need to deal with Dex2OAT. Meanwhile, Dex2OAT is applied in shell adding and peeling. The dex2OAT code can be modified for better peeling.