写点什么

稀疏镜像在 OpenHarmony 上的应用

  • 2023-02-08
    上海
  • 本文字数:3520 字

    阅读完需:约 12 分钟

一、稀疏镜像升级背景

常用系统镜像格式为原始镜像,即 RAW 格式。镜像体积比较大,在烧录固件或者升级固件时比较耗时,而且在移动设备升级过程时比较耗费流量。为此,将原始镜像用稀疏描述,可以大大地缩减镜像体积,省时省流量。


二、稀疏镜像原理

1、稀疏镜像的概念

原始镜像:即 raw image,完整的 ext4 分区镜像,包含很多全零的无效填充区

稀疏镜像:即 sparse image,将 raw ext4 进行稀疏描述,因此尺寸比较小,制作目录有多少文件就计算多少,没有全零填充


2、稀疏镜像格式


稀疏镜像数据格式:首先是 sparse_header 占用 28byte,然后是 12byte 的 chunk_header,同样这 chunk_header 的类型决定了后面跟着的数据,如果读到数据是 0xCAC1 意味着后面是本身的 raw_data,如果是 0xCAC3,则后面 num 为 0,接着再 0xCAC2 意味着后面填充 4byte 的内容。


三、实现稀疏镜像升级方案

版本基线:OpenAtom OpenHarmony(以下简称“OpenHarmony”) 3.1 Release

代码路径:https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/OpenHarmony-v3.1-release.md


1、稀疏镜像烧录

(1)生成稀疏格式镜像

有 2 种方法可以生成稀疏镜像:

1)修改文件 build/ohos_var.gni 中,sparse_image=true


2)编译命令增加--sparse-image 字段,如./build.sh --product-name=xxx --sparse-image

(2)增加稀疏格式转换工具

在目录 build/ohos/images/mkimage 中增加文件 img2simg,该工具用于编译完成后将 raw 镜像转换为 sparse 格式,并设置权限为 777。

(3)编译后的镜像对比


编译出的镜像格式为 sparse 格式,镜像大小相比 raw 格式明显变小。

(4)烧录稀疏镜像

烧录稀疏镜像方法和烧录原始镜像方法一致。

稀疏镜像本身是不能直接挂载的,在烧录过程中通过 uboot 将稀疏格式镜像还原为原始镜像,然后写到磁盘中,系统启动后可挂载对应的镜像。


2、稀疏镜像升级

升级包采用稀疏镜像制作。

(1)修改升级包制作工具官方升级包工具不支持生成稀疏镜像的升级包,修改升级包工具,生成稀疏格式的升级包。.\base\update\packaging_tools\image_class.py



按照上图所示注释代码


(2)生成稀疏镜像升级包

和全量镜像升级包制作方法一致。

参考:https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-ota-guide.md#%E6%A0%87%E5%87%86%E7%B3%BB%E7%BB%9F%E5%8D%87%E7%BA%A7%E5%8C%85%E5%88%B6%E4%BD%9C

(3)适配 updater 组件中稀疏镜像功能

● 增加写稀疏镜像分支

.\base\update\updater\services\applypatch\data_writer.cpp

写数据函数 CreateDataWriter 增加写稀疏镜像分支

case WRITE_SPARSE:{    std::unique_ptr<SparseWriter> writer(std::make_unique<SparseWriter>(partitionName));    return std::move(writer);}
复制代码


● 增加稀疏镜像类声明

.\base\update\updater\services\applypatch\raw_writer.h

增加稀疏镜像类声明及相关变量定义

typedef struct sparse_header {  uint32_t  magic;      /* 0xed26ff3a */  uint16_t  major_version;  /* (0x1) - reject images with higher major versions */  uint16_t  minor_version;  /* (0x0) - allow images with higer minor versions */  uint16_t  file_hdr_sz;    /* 28 bytes for first revision of the file format */  uint16_t  chunk_hdr_sz;   /* 12 bytes for first revision of the file format */  uint32_t  blk_sz;     /* block size in bytes, must be a multiple of 4 (4096) */  uint32_t  total_blks; /* total blocks in the non-sparse output image */  uint32_t  total_chunks;   /* total chunks in the sparse input image */  uint32_t  image_checksum; /* CRC32 checksum of the original data, counting "don't care" */                /* as 0. Standard 802.3 polynomial, use a Public Domain */                /* table implementation */} sparse_header_t; #define SPARSE_HEADER_MAGIC 0xed26ff3a #define CHUNK_TYPE_RAW      0xCAC1#define CHUNK_TYPE_FILL     0xCAC2#define CHUNK_TYPE_DONT_CARE    0xCAC3#define CHUNK_TYPE_CRC32    0xCAC4 typedef struct chunk_header {  uint16_t  chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */  uint16_t  reserved1;  uint32_t  chunk_sz;   /* in blocks in output image */  uint32_t  total_sz;   /* in bytes of chunk input file including chunk header and data */} chunk_header_t; class SparseWriter : public DataWriter {public:    virtual bool Write(const uint8_t *addr, size_t len, WriteMode mode, const std::string &partitionName);     explicit SparseWriter(const std::string partitionName) : offset_(0), fd_(-1), partitionName_(partitionName) {}     virtual ~SparseWriter()    {        offset_ = 0;        if (fd_ > 0) {            fsync(fd_);            close(fd_);        }        fd_ = -1;    }private:    int WriteInternal(int fd, const uint8_t *data, size_t len, const std::string &partitionName);     SparseWriter(const SparseWriter&) = delete;     const SparseWriter& operator=(const SparseWriter&) = delete;    off64_t offset_;    int fd_;    std::string partitionName_;};
复制代码


● 增加稀疏镜像类实现

.\base\update\updater\services\applypatch\raw_writer.cpp

增加稀疏镜像类实现及相关变量定义,原有代码不变

typedef struct sparse_header {  uint32_t  magic;      /* 0xed26ff3a */  uint16_t  major_version;  /* (0x1) - reject images with higher major versions */  uint16_t  minor_version;  /* (0x0) - allow images with higer minor versions */  uint16_t  file_hdr_sz;    /* 28 bytes for first revision of the file format */  uint16_t  chunk_hdr_sz;   /* 12 bytes for first revision of the file format */  uint32_t  blk_sz;     /* block size in bytes, must be a multiple of 4 (4096) */  uint32_t  total_blks; /* total blocks in the non-sparse output image */  uint32_t  total_chunks;   /* total chunks in the sparse input image */  uint32_t  image_checksum; /* CRC32 checksum of the original data, counting "don't care" */                /* as 0. Standard 802.3 polynomial, use a Public Domain */                /* table implementation */} sparse_header_t; #define SPARSE_HEADER_MAGIC 0xed26ff3a #define CHUNK_TYPE_RAW      0xCAC1#define CHUNK_TYPE_FILL     0xCAC2#define CHUNK_TYPE_DONT_CARE    0xCAC3#define CHUNK_TYPE_CRC32    0xCAC4 typedef struct chunk_header {  uint16_t  chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */  uint16_t  reserved1;  uint32_t  chunk_sz;   /* in blocks in output image */  uint32_t  total_sz;   /* in bytes of chunk input file including chunk header and data */} chunk_header_t; class SparseWriter : public DataWriter {public:    virtual bool Write(const uint8_t *addr, size_t len, WriteMode mode, const std::string &partitionName);     explicit SparseWriter(const std::string partitionName) : offset_(0), fd_(-1), partitionName_(partitionName) {}     virtual ~SparseWriter()    {        offset_ = 0;        if (fd_ > 0) {            fsync(fd_);            close(fd_);        }        fd_ = -1;    }private:    int WriteInternal(int fd, const uint8_t *data, size_t len, const std::string &partitionName);     SparseWriter(const SparseWriter&) = delete;     const SparseWriter& operator=(const SparseWriter&) = delete;    off64_t offset_;    int fd_;    std::string partitionName_;};
复制代码


3、验证稀疏镜像升级

(1)拷贝升级包

将制作的稀疏镜像升级包通过 HDC 工具推进系统 data 目录,并修改文件名为 updater.zip,路径如下:/data/updater/updater.zip

(2)启动升级

系统启动后,在命令行工具输入如下命令启动升级

reboot updater:--update_package=/data/updater/updater.zip

输入命令后,系统重启,进入升级页面,等待升级完成。


本文介绍了 OpenHarmony 系统中实现稀疏镜像升级的方法,理解稀疏镜像原理及稀疏镜像还原方法可以快速在自己的系统中应用稀疏镜像升级,提高系统升级速度。


用户头像

OpenHarmony开发者官方账号 2021-12-15 加入

OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展

评论

发布
暂无评论
稀疏镜像在OpenHarmony上的应用_OpenHarmony_OpenHarmony开发者_InfoQ写作社区