ART深入浅出3--了解Boot.art和boot-*.art

boot.art&boot.oat external/vogar/src/vogar/ModeId.java: // $BOOTCLASSPATH defined by system/core/rootdir/init.rc 而在~/android-6.0.1_r62/out/target/product/generic/root/init.rc中有: 7 import /init.environ.rc在~/android- 阅读详情

本文基于Android 7.1,不过因为从BSP拿到的版本略有区别,所以本文提到的源码未必与读者找到的源码完全一致。本文在提供源码片断时,将按照 <源码相对android工程的路径>:<行号> <类名> <函数名> 的方式,如果行号对不上,请参考类名和函数名来找到对应的源码。

在Android7.0之前,所有bootclasspath指定的库会被同一编译成为boot.oat和boot.art两个文件。其中boot.oat包含了编译后的机器码指令,而boot.art文件,则是一个类对象映像。boot.art内包含了所有framework/base/preloaded-classes文件列出的所有类。这些类会被一次性的载入到内存中,并可以被直接使用。
在Android7.0及以后,boot.art和boot.oat被分成了以boot-<packagename>.oat/art方式的多个库。当有一个库被更新,不至于整个boot.art/boot.oat被更新。
当然,你有时也看不到这些被分开的boot.art/boot.oat库,这是因为,Android7.0可以通过参数来控制。
为了简便,我们只讨论所有bootclasspath包作成一个boot.art/boot.art的情况。
除此之外,如果在编译ROM时,选择打开ODEX,那么,编译程序就会生成boot.oat/boot.art,连同system/app, system/priv-app下面的程序,都会生成它们的oat文件。一般boot.oat/boot.art(可能是boot-.oat, boot- .art) 会放在 /system/framework/arm64 或者 /system/framework/arm下面。在系统初始化时,这些预编译好的oat/art文件会被拷贝到/data/dalvik-cache下面。在android7.0上,则会直接读取它们,不用再拷贝了。

boot.art文件的加载

为了探究boot.art文件的格式,我们首先要大致了解下它的加载过程。
boot.art文件是在创建heap的时候加载的。在构造函数Heap::Heap,我们可以看到如下的代码:
art/gc/heap.cc:278 Heap::Heap

  // Load image space(s).
  if (!image_file_name.empty()) {
   ....
    for (size_t index = 0; index < image_file_names.size(); ++index) {
      std::string& image_name = image_file_names[index];
      std::string error_msg;
      space::ImageSpace* boot_image_space = space::ImageSpace::CreateBootImage(
          image_name.c_str(),
          image_instruction_set,
          index > 0,
          &error_msg);
....
  }

我把其中很多代码都省略了,我们只看我们关心的代码space::ImageSpace::CreateBootImage 函数。
heap把内存分成了若干的space,每个space管理一大块内存,每个space下面都有自己的内存分配和回收算法,这样可以应对不同的内存需求。比如,有些内存一但分配,就不释放的,如为class,method, field这些元对象分配的内存;一些大内存对象,如图片的像素数组等,一个对象就占用很多内存;或者是那些频繁创建但是很快丢弃的对象。等等。
Boot.art内部保存的,主要是一些class,method,field,还有一些非常基础的类对象,比如用于管理dex数据的dexcache对象等,这些对象,一旦分配,就不会释放,不仅是在一个应用的生命周期,而是在整个系统的周期内。也就是说,只有手机关机了,它们才会被丢弃掉。故此,ART将这些数据做成映像,系统一启动就把它们载入到内存,而且是zygote进程的内存,这样所有zygote的子进程就可以直接享用这些数据了。
下面
art/runtime/gc/space/image_space.cc:1149 ImageSpace::Init

ImageSpace* ImageSpace::CreateBootImage(const char* image_location,
                                        const InstructionSet image_isa,
                                        bool secondary_image,
                                        std::string* error_msg) {
....
  bool found_image = FindImageFilename(image_location, image_isa, &system_filename,
                                       &has_system, &cache_filename, &dalvik_cache_exists,
                                       &has_cache, &is_global_cache);

....
  ImageSpace* space;
  bool relocate = Runtime::Current()->ShouldRelocate();
  bool can_compile = Runtime::Current()->IsImageDex2OatEnabled();
  if (found_image) {
....
      space = ImageSpace::Init(image_filename->c_str(),
                               image_location,
                               !(is_system || relocated_version_used),
                               /* oat_file */nullptr,
                               error_msg);
   ....
    return space;
  }
}

去除一些逻辑,可以看到一个关键函数ImageSpace::Init 其他的逻辑我们现在不关心。

ImageSpace* ImageSpace::Init(const char* image_filename,
                             const char* image_location,
                             bool validate_oat_file,
                             const OatFile* oat_file,
                             std::string* error_msg) {
....
  ImageHeader temp_image_header;
  ImageHeader* image_header = &temp_image_header;
  {
    TimingLogger::ScopedTiming timing("ReadImageHeader", &logger);
    bool success = file->ReadFully(image_header, sizeof(*image_header));
    if (!success || !image_header->IsValid()) {
      *error_msg = StringPrintf("Invalid image header in '%s'", image_filename);
      return nullptr;
    }
  }
  ...

  std::vector<uint8_t*> addresses(1, image_header->GetImageBegin());
  if (image_header->IsPic()) {
    // Can also map at a random low_4gb address since we can relocate in-place.
    addresses.push_back(nullptr);
  }

  // Note: The image header is part of the image due to mmap page alignment required of offset.
  std::unique_ptr<MemMap> map;
  std::string temp_error_msg;
  for (uint8_t* address : addresses) {
    TimingLogger::ScopedTiming timing("MapImageFile", &logger);
    // Only care about the error message for the last address in addresses. We want to avoid the
    // overhead of printing the process maps if we can relocate.
    std::string* out_error_msg = (address == addresses.back()) ? &temp_error_msg : nullptr;
    const ImageHeader::StorageMode storage_mode = image_header->GetStorageMode();
    if (storage_mode == ImageHeader::kStorageModeUncompressed) {
      map.reset(MemMap::MapFileAtAddress(address,
                                         image_header->GetImageSize(),
                                         PROT_READ | PROT_WRITE,
                                         MAP_PRIVATE,
                                         file->Fd(),
                                         0,
                                         /*low_4gb*/true,
                                         /*reuse*/false,
                                         image_filename,
                                         /*out*/out_error_msg));
    } else {
      ....//解压再映射部分的代码,不是核心功能,不去管他。
    }
    if (map != nullptr) {
      break;
    }
  }

....
  {
    TimingLogger::ScopedTiming timing("RelocateImage", &logger);
    if (!RelocateInPlace(*image_header,
                         map->Begin(),
                         bitmap.get(),
                         oat_file,
                         error_msg)) {
      return nullptr;
    }
  }
  // We only want the mirror object, not the ArtFields and ArtMethods.
  std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename,
                                                   image_location,
                                                   map.release(),
                                                   bitmap.release(),
                                                   image_end));

  ....
  return space.release();
}

我去除了很多逻辑判断的代码,以及解压压缩image的代码。去掉这些后,我们发现,它实际上只有很简单的两个步骤:

  1. 解析ImageHeader,拿到基本信息
  2. 将image映射到内存中,映射的时候需要映射到ImageHeader存好的地址。
    Android N 支持PIC模式,即可重定向Image的位置。这是个可选项。我们暂时不讨论PIC模式,先了解固定地址映射的情况后,再去了解它。

boot.art的文件格式

art/runtime/image.h:73

class PACKED(4) ImageHeader {
....
private:
  static const uint8_t kImageMagic[4];
  static const uint8_t kImageVersion[4];

  uint8_t magic_[4];
  uint8_t version_[4];

  // Required base address for mapping the image.
  uint32_t image_begin_;

  // Image size, not page aligned.
  uint32_t image_size_;

  // Checksum of the oat file we link to for load time sanity check.
  uint32_t oat_checksum_;

  // Start address for oat file. Will be before oat_data_begin_ for .so files.
  uint32_t oat_file_begin_;

  // Required oat address expected by image Method::GetCode() pointers.
  uint32_t oat_data_begin_;

  // End of oat data address range for this image file.
  uint32_t oat_data_end_;

  // End of oat file address range. will be after oat_data_end_ for
  // .so files. Used for positioning a following alloc spaces.
  uint32_t oat_file_end_;

  // Boot image begin and end (app image headers only).
  uint32_t boot_image_begin_;
  uint32_t boot_image_size_;

  // Boot oat begin and end (app image headers only).
  uint32_t boot_oat_begin_;
  uint32_t boot_oat_size_;

  // TODO: We should probably insert a boot image checksum for app images.

  // The total delta that this image has been patched.
  int32_t patch_delta_;

  // Absolute address of an Object[] of objects needed to reinitialize from an image.
  uint32_t image_roots_;

  // Pointer size, this affects the size of the ArtMethods.
  uint32_t pointer_size_;

  // Boolean (0 or 1) to denote if the image was compiled with --compile-pic option
  const uint32_t compile_pic_;

  // Boolean (0 or 1) to denote if the image can be mapped at a random address, this only refers to
  // the .art file. Currently, app oat files do not depend on their app image. There are no pointers
  // from the app oat code to the app image.
  const uint32_t is_pic_;

  // Image section sizes/offsets correspond to the uncompressed form.
  ImageSection sections_[kSectionCount];

  // Image methods, may be inside of the boot image for app images.
  uint64_t image_methods_[kImageMethodsCount];

  // Storage method for the image, the image may be compressed.
  StorageMode storage_mode_;

  // Data size for the image data excluding the bitmap and the header. For compressed images, this
  // is the compressed size in the file.
  uint32_t data_size_;
....
};

内容虽然多,但是我们可以分组了解

  uint8_t magic_[4];
  uint8_t version_[4];

这个没什么好说的,Android N上固定是 “art\n” 和 “030\0”。

  // Required base address for mapping the image.
  uint32_t image_begin_;

  // Image size, not page aligned.
  uint32_t image_size_;

这是Image本身的大小和映射的开始地址。Android N支持PIC,在是PIC模式下,ART试图加载image到image_begin_ 处,如果失败,就会把image加载到任意地址,然后在进行重定位。
当然,这个“任意”地址也是有限制的。在ART内部,ART直接用Object的指针访问它们,即Object的引用值就是这个Object在内存中的地址。不过,按照java规范的要求,一个Object的引用只能是4字节,所以,在64位系统中,Object在内存中只能存储在高32为0的地址内,这也就是说,image以及所有的java对象都只能在这个范围内分配。

  // Checksum of the oat file we link to for load time sanity check.
  uint32_t oat_checksum_;

  // Start address for oat file. Will be before oat_data_begin_ for .so files.
  uint32_t oat_file_begin_;

  // Required oat address expected by image Method::GetCode() pointers.
  uint32_t oat_data_begin_;

  // End of oat data address range for this image file.
  uint32_t oat_data_end_;

  // End of oat file address range. will be after oat_data_end_ for
  // .so files. Used for positioning a following alloc spaces.
  uint32_t oat_file_end_;

这4个值和boot.art对应的boot.oat的信息。boot.art和boot.oat必须是对应的,否则就会出现问题。为此,boot.art中存储了它对应的boot.oat的校验和。每次加载时必须进行校验,通过后才可以加载,否则就会退出系统。
oat_file_begin的地址和oat_data_begin是有一定区别的。oat file借用了elf文件的格式,它可以看作一个标准的elf文件。oat_file_begin是这个elf文件的加载地址。oat真正的数据,是保存在elf文件的”.oatdata”以及和它挨着的”.oattext”段, oat_data_begin,就是oatdata的地址。一般oat_file_begin和oat_data_begin相差0x1000,这个空间映射的是elf文件的头信息。

  // Boot image begin and end (app image headers only).
  uint32_t boot_image_begin_;
  uint32_t boot_image_size_;

  // Boot oat begin and end (app image headers only).
  uint32_t boot_oat_begin_;
  uint32_t boot_oat_size_;

在只有app有art的情况下才使用。实际上,只有从Android N开始才正式支持app有image,不过,我还没有看到过实际产品中开启app的image。所以不用管他了。

  // The total delta that this image has been patched.
  int32_t patch_delta_;

这个值有patchoat命令修改,在Android N上用的少了。没有太大意义。

  uint32_t image_roots_;

  // Pointer size, this affects the size of the ArtMethods.
  uint32_t pointer_size_;

image_roots_的绝对地址,这是一个Object[]数组,里面包含了最基本的roots对象,后面详细介绍。

c++
// Image section sizes/offsets correspond to the uncompressed form.
ImageSection sections_[kSectionCount];

ImageSection保存了一些可以优化的东西,不是关键。
c++
// Image methods, may be inside of the boot image for app images.
uint64_t image_methods_[kImageMethodsCount];

这是保存一些运行时的method。所谓运行时的method,指不是由用户代码生成,而是在art内部定义,用于完成一些特殊任务的方法。
c++
enum ImageMethod {
kResolutionMethod,
kImtConflictMethod,
kImtUnimplementedMethod,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
kImageMethodsCount, // Number of elements in enum.
};

比如ResolutionMethod,用于解析一个方法。当加载一个dex文件或者class的时候,dex文件内引用到的method的初值都被设置为该运行时函数。这个函数被调用时,会先解析出真正的函数,然后在转入进去。
CalleeSaveMethod是用于保存当前调用的java函数信息。比如,java代码抛出了一个异常,该异常对象需要保存抛出位置的调用栈列表。这需要ART遍历当前的调用栈。于是,ART就会生成一个CalleeSaveMethod方法,将当前正在使用的寄存器全部保存到这个CalleeSaveMethod函数的栈上,然后再进行遍历。这是Android M以后才加入的特性。

image_roots

image_roots_是一个Object[]数组,它的成员定义是
c++
enum ImageRoot {
kDexCaches,
kClassRoots,
kImageRootsMax,
};

这两个成员指出的都是数组对象。

DexCaches

通过 ImageHeader::GetImageRoot(ImageHeader::kDexCaches)得到DexCache[] 。
DexCache是定义在 libcore/libart/src/main/java/lang/DexCache.java中的一个核心对象。它是Dex文件的内存对象,将Dex文件内常用数据缓存成可以直接使用的各种对象。ART用这些对象加载类、访问代码等。

ClassRoots

通过ImageHeader::GetImageRoot(ImageHeader::kClassRoots)获得,保存在ClassLinker的class_roots_成员内。
这是一个Class[] 数组对象,它的成员都是java/lang下最基本的类,比如Class, Object, String, Reference,以及一些特殊的数组类,Class[], Object[], 和基础对象,boolean.class, int.class,void.class等等。

Image的主体内容

Image剩下的部分,都是一些class了。这些内容是从framework/base/preloaded-classes文件中列出的那些类。这些内容加载到内存后,就可以直接被访问了。它们的结构和class对象的结构是完全一样的,所不同的就是它们的数据全部被压缩到了一起。

【个人笔记一】ART系统类的编译解析加载探究 在ART上用YAHFA、Legend以及一个java层实现的Andix:ART深度探索开篇:从Method Hook谈起对系统中不同的类进行hook,发现除了framework层的类(如telephonymanager)和应用中的类有效外,对于java核心库的类(如IOBridge和Class等)的hook都无效,所以我就以telephonymanager和IOBridge这两个类为例,试图从编译 阅读详情

相关推荐

Android ART编译模式解析

ART实际就是Android runtime的缩写,他是Android版本新的虚拟机。

u010345983的博客 4074

Android10中的boot*.art和boot*.oat加载过程

简介   在Android7.0之前,所有bootclasspath指定的库会被同一编译成为boot.oat和boot.art两个文件。其中boot.oat包含了编译后的机器码指令,而boot.art文件,则是一个类对象映像。boot.art内包含了所有framework/base/preloaded-classes文件列出的所有类。这些类会被一次性的载入到内存中,并可以被直接使用。   在Android7.0及以后,boot.art和boot.oat被分成以boot-{packagename}.oat/a

Invoker123的博客 6021

第 18 章:ART 运行时

Android运行时(ART)是Android应用的执行环境,负责加载和执行DEX字节码。ART通过多层级编译策略(解释器、JIT、AOT)和并发垃圾回收(如CC和CMC收集器)优化性能。关键组件包括类链接器、dex2oat编译器、JIT编译器和内存管理系统。ART支持模块化更新,并通过配置文件引导优化(PGO)提升应用性能。调试能力基于JVMTI,提供断点、类重定义等功能。Android 17引入了多项改进,如分代标记-压缩GC、禁止反射修改static final字段、DEX容器格式V41等。ART架构

dengfuma的专栏 282

art虚拟机启动过程分析

android art jvm

nbsp22的博客 3873

水星路由器MER1200G刷机后回退原厂固件全攻略(TTL串口救砖指南)

本文详细介绍了水星路由器MER1200G刷机后通过TTL串口回退原厂固件的完整流程。从硬件诊断、TTL连接、U-Boot操作到固件处理,提供了一套完整的救砖方案,帮助用户解决刷机失败后的各种问题,恢复路由器原始功能。

weixin_30599769的博客 435

如何构建智能聊天系统

聊天分为听、思考、读,简单的通过ASR、LLM、TTS三类模型的组合可以实现,最近openai推出支持多模态的GPT-4o模型,可以把三个模型真正融合成在一起。现在市面上的模型百花齐放,各有所长。要实现可落地的方案,需要结合业务,验证模型效果,同时也要考虑方案的可行性,有些模型在国内能用,有些在国内不能用。

xsgnzb的专栏 2108

android 8.0单编framework 等模块只会更新arm/boot.art boot.ota文件,且 framework只会1KB

今天在更新本地代码后,单编framework时 发现编译并不是更新framework .jar文件,且framework .jar只有1KB, 编译信息提示也显示 install :out/target/product/xxxxx/system/framework/arm/boot.art ,因为是在framework 修改功能,不便于每次修改后都整编,或是remake 项目,因为那样速...

蚁人日记 2928

Matplotlib字体警告终结者:为什么总提示DejaVu Sans?5种场景解决方案大全

本文深入解析Matplotlib中常见的DejaVu Sans字体警告问题,并提供5种典型场景的完整解决方案。从理解字体系统的三层架构和缓存机制,到解决中文显示、远程服务器部署、TeX渲染、缓存优化及生产环境配置等实际问题,帮助开发者彻底摆脱字体警告困扰,实现稳定可靠的数据可视化。

view3的博客 502

Android运行时ART加载类和方法的过程分析

既然ART运行时执行的都是翻译DEX字节码后得到的本地机器指令了,为什么还需要在OAT文件中包含DEX文件,并且将它加载到内存去呢?这是因为ART运行时提供了Java虚拟机接口,而要实现Java虚拟机接口不得不依赖于DEX文件ART运行时查找类方法的本地机器指令的过程为了方便描述,我们将DEX文件中描述的类和方法称为DEX类(Dex Class)和DEX方法(Dex Method),而将在OAT文件中描述的类和方法称为OAT类(Oat Class)和OAT方法(Oat Method)。

博客 1415

R语言实战:非正态数据下的Scheirer–Ray–Hare检验全流程解析

本文详细解析了在R语言中执行Scheirer–Ray–Hare检验的全流程。当数据不满足正态分布假设时,该非参数检验是传统双因素方差分析的有效替代方案。文章从原理、R环境配置、数据准备、代码实现、结果解读到事后比较与可视化,提供了完整的实战指南,帮助研究者稳健地分析多因素实验设计中的主效应和交互效应。

cc789的博客 406

Python实现飞书机器人定时发送文本、图片等群消息

python实现飞书群自动发送告警消息

tyh_keephunger的博客 2万+

LIEF 对 Android ART 文件格式的解析支持:从 ART Header 到跨语言 API 实战指南

ART(Android Runtime)既是 Android 的运行时名称,也是一种用于加速系统启动的**二进制镜像格式**。本指南以 LIEF 项目的 ART 模块文档为主线,系统讲解 ART 格式的来历与内部结构(Header、Image Sections、Image Methods 等)、LIEF 提供的 C++/Python 双语言 API(`is_art`/`version`/`andr

gitblog_01144的博客 354

关于HC32F460 输出可调占空比PWM波遇到的问题记录

文章目录问题记录一、问题分析二、解决方法总结 问题记录 芯片:HC32F460系列 功能:PWM电机调速 最近产品开发,需要用到HC32的PWM输出来控制电机的转速。参考官方的例程很快就完成了相关的功能,但是,后面在测试,重复开关电机的时候,发现电机的转速时大时小。 一、问题分析 一开始,怀疑是相关寄存器的设置出错导致的问题。因此在设置PWM输出时加上LOG打印,上机测试并没有发现问题。 用示波器抓取波形,这是正常状态下的波形(上电默认配置成5kHz,70%占空比输出) 这是转速较小时的波形输出 .

Top0_0lll的博客 6165

Android运行时ART加载OAT文件的过程分析

Android运行时ART加载OAT文件的过程分析

ufryyfdf的博客 460

机器人关节电机发热难题:从工程化角度拆解热管理解决方案(下)

摘要:本文系统分析了机器人关节电机与驱动系统的热管理方案,重点解决局部热点问题。针对不同功率场景提出了热管/均热板散热(适用于中小功率)和液冷散热(适用于高功率)的具体实施方案,详细比较了结构参数、材料选择、安装工艺和散热效果。特别强调了电机-驱动协同热管理的重要性,提出"工况联动+热路径共享"的核心理念,包括一体化散热结构设计和动态控制策略。最后介绍了热仿真与测试验证方法,确保方案的有效落地。通过系统级热管理,可显著降低温升(热点区域降温30-60℃),同时优化体积和能耗。

bother3000的博客 3329

逆概率加权法(Inverse Probability Weighting, IPW)的原理及R实现

逆概率加权(IPW)是一种用于解释由于非随机选择观测值或人群信息的非随机缺失而造成的缺失和选择偏差的方法。原理:这种方法可以通过对观察值的加权来修正分析,使其具有被选中的概率。IPW是基于这样一个假设,即整个研究人群都有可以预测纳入概率(非遗漏)的个体信息,因此,在考虑到这些信息后,我们可以仅从非遗漏的观察值开始对整个目标人群进行推断。计算的程序如下:首先,我们考虑整个研究人群,用逻辑回归模型计算非失访信息的概率,其中响应是非失访,协变量是其可能的预测因素。每个受试者的权重是由预测概率的倒数给出的。然后使用

Christina 5万+

LIEF 的 Python API 解析 Android ART 文件:is_art / version / parse 与 Header 字段全解

本文围绕 LIEF(Library to Instrument Executable Formats)为 Android ART(Android Runtime)镜像文件提供的 Python 绑定展开,系统讲解从"判断文件是不是 ART"、"读取 ART 版本号"、"映射到 Android 系统版本",到"解析出 `lief.ART.File` 对象"并逐字段解读 `lief.ART.Header

gitblog_01199的博客 68

3D slicer查看形变场

3Dslice显示数据和形变场 将需要可视化的数据也导入3Dslice,注意描述为volume(图1a),如果没有显示是因为路径中不能有中文,也就是moving图像。 (b) 图1、数据导入形变场和 将相应的形变场数据直接拖入3Dslice,并修改描述为形变场(图1b)。 点击transform菜单图2(a),然后勾选形变场可视化图2(b)。 (b) 图2...

fanre的专栏 1947

ART-PI调试记录---ART-PI OLED驱动流程

ART-PI OLED驱动流程(RT-Studio平台) 最近RT-Thread举办了一个RTT全连接大赛,也是借着这次机会,申请了一块RTT的STM32H750为主控芯片的RTT核心板,做工还是很漂亮的,老规矩,话不多说,上干货! 新建工程就不多说了,有问题的话,加我好友,小飞哥手把手教,哈哈,工程建立后 1、double click 方框中的配置选项,进入工具箱界面,点击ADD 按钮,在弹出的RT-Thread软件包界面搜索框输入u8g2,点击添加,软件包已添加进来 ...

qq_16519885的博客 992

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

QSDK art分区地址映射

U-Boot 启动过程及简单代码分析 这里以 AR7241 的 U-Boot 为例 MIPS 架构简介 MIPS 地址空间: 这里说的是地址空间,不是内存空间。内存只是映射在一部分地址空间上而已。 内存分为4段 (Kuseg、Kseg0、Kseg1、Kseg2),其中 Kseg0 (0x80000000 ~ 0x9fffffff) 为缓存段,直接映射在物理地址段上。 Kseg1

yubing_615的专栏 3008

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

LIEF 解析 Android 四大格式(DEX/OAT/VDEX/ART)实战指南

本指南以 LIEF 官方文档的 [Android 格式索引](https://link.gitcode.com/i/c585d76a7b4de2412950a097ea7c07f2) 为主线,系统讲解 LIEF 对 Android 平台四种关键二进制格式——**DEX**(Dalvik 可执行文件)、**OAT**(ART 编译产物,本质是 ELF)、**VDEX**(Android 8.0+ 的

gitblog_00205的博客 416

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

STM32F4 BOOT启动模式选择不同运行方式

本文深入剖析STM32F4的BOOT启动机制,涵盖BOOT0和BOOT1引脚的硬件采样、三种启动源配置及其应用场景。详细讲解主闪存、系统存储器和SRAM启动的工作原理,并结合实战案例说明ISP烧录、OTA升级与SRAM调试的实现方法。强调PCB设计中的抗干扰措施与最佳实践,帮助开发者规避常见启动问题。

weixin_34471637的博客 632

Android执行时ART载入OAT文件的过程分析

在前面一文中,我们介绍了Android执行时ART,它的核心是OAT文件。OAT文件是一种Android私有ELF文件格式,它不仅包括有从DEX文件翻译而来的本地机器指令。还包括有原来的DEX文件内容。这使得我们无需又一次编译原有的APK就能够让它正常地在ART里面执行。也就是我们不须要改变原来的APK编程接口。本文我们通过OAT文件的载入过程分析OAT文件的结构,为后面分析A...

weixin_30681121的博客 147

AR/QCA SPI 启动原理和 ART 地址定位原理

在执行跳转后,U-Boot 会立即关闭 0x1fc00000 处 Flash 的重映射,因此 U-Boot 必须在进入 C 环境 (即使用栈帧) 之前完成跳转,否则栈中会保留 0xbfc00000 相关的地址,在禁用 Flash 重映射后会失效。但是根据第4节的描述,CPU 初始化时,kseg0 段的缓存并未初始化,不能访问。实际上,Flash 对于地址有个回绕功能,也就是说,如果给定的地址超过了 Flash 的地址范围,那么 Flash 会自动让地址变成 0,即又从头开始。

血色天空的专栏 467

深入ART虚拟机:解读Android hprof文件里的Heap-App/Image/Zygote分区与GC Root

本文深入解析ART虚拟机中hprof文件的Heap-App/Image/Zygote分区与GC Root机制,揭示Android内存管理的独特设计。通过分析堆分区特性、GC Root类型及内存泄漏诊断策略,帮助开发者优化应用性能,提升内存分析效率。

weixin_30703911的博客 399

SPIRAN ART SUMMONER图像生成Java开发实战:企业级应用集成

本文介绍了如何在星图GPU平台上自动化部署🔮 SPIRAN ART SUMMONER图像生成镜像,实现企业级AI图像生成能力集成。通过Java技术栈与微服务架构,企业可快速构建高并发应用,自动化生成商品海报、内容配图等营销素材,显著提升内容创作效率。

weixin_35639680的博客 82
上一篇: ART深入浅出2 -- 认识和了解Runtime Options
下一篇: ART深入浅出4--了解Dex文件格式(1)
漂流的代码
博客等级 码龄23年 188粉丝 99原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值