稀疏镜像在OpenHarmony上的应用

开源项目 openharmony是每个人的 openharmony   陈甲印
鸿湖万联高级技术专家
鸿湖万联产品推荐官
  一、稀疏镜像升级背景
常用系统镜像格式为原始镜像,即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)修改升级包制作工具官方升级包工具不支持生成稀疏镜像的升级包,修改升级包工具,生成稀疏格式的升级包。.aseupdatepackaging_toolsimage_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组件中稀疏镜像功能●增加写稀疏镜像分支.aseupdateupdaterservicesapplypatchdata_writer.cpp写数据函数createdatawriter增加写稀疏镜像分支case write_sparse:{ std::unique_ptr writer(std::make_unique(partitionname)); return std::move(writer);} ●增加稀疏镜像类声明.aseupdateupdaterservicesapplypatch aw_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_;}; ●增加稀疏镜像类实现.aseupdateupdaterservicesapplypatch aw_writer.cpp增加稀疏镜像类实现及相关变量定义,原有代码不变bool sparsewriter::write(const uint8_t *addr, size_t len, writemode mode, const std::string &partitionname){    if (addr == nullptr) {        log(error) << sparsewriter: invalid address.;        return false;    }    if (len == 0) {        log(info) << sparsewriter: write length is 0, skip.;        return false;    }    if (fd_ < 0) {        fd_ = openpartition(partitionname_);        if (fd_ = 0, return false);    return true;}  int sparsewriter::writeinternal(int fd, const uint8_t *data, size_t len, const std::string &partitionname){    uint32_t written = 0;    sparse_header_t *sparse_header;    chunk_header_t *chunk_header;    unsigned int chunk;    void *membuf = null;    uint32_t *fill_buf = null;    uint32_t fill_val;    uint32_t bytes_written = 0;    uint32_t total_bytes = 0;    uint32_t blk = 0;    uint32_t chunk_data_sz = 0;    uint32_t blkcnt = 0;    uint32_t blks = 0;    uint32_t total_blocks = 0;    uint32_t addr_offset = 0;    uint32_t fill_buf_num_blks = 0;      uint32_t block_size = 4096;    uint32_t block_count = 524288;    uint32_t i;    uint32_t j;    int ret = lseek64(fd, offset_, seek_set);    updater_file_check(ret != -1, rawwriter: failed to seek file to << offset_, return -1);    fill_buf_num_blks = config_fastboot_flash_fillbuf_size / block_size;     log(info) << writeinternal offset_ file_hdr_sz > sizeof(sparse_header_t)) {        /*         * skip the remaining bytes in a header that is longer than         * we expected.         */        data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));    }    log(info) << === sparse image header ===;    log(info) << magic:   sizeof(chunk_header_t)) {            /*             * skip the remaining bytes in a header that is longer             * than we expected.             */            data += (sparse_header->chunk_hdr_sz -                 sizeof(chunk_header_t));        }        chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;        blkcnt = chunk_data_sz / block_size;        switch (chunk_header->chunk_type) {        case chunk_type_raw:            if (chunk_header->total_sz !=                (sparse_header->chunk_hdr_sz + chunk_data_sz)) {                log(error) < 0 + block_count) {                log(error) << request would exceed partition size!;                return -1;            }            addr_offset = blk * block_size;            ret = lseek64(fd, offset_ + addr_offset, seek_set);            if (ret < 0) {                log(error) << failed to seek file to << addr_offset << error= << strerror(errno);                return -1;            }            written = write(fd, data, blkcnt * block_size);            if (written < 0) {                log(error) total_sz !=                (sparse_header->chunk_hdr_sz + sizeof(uint32_t))) {                log(error) << bogus chunk size for chunk type fill total_sz err chunk_sz;            break;        case chunk_type_crc32:            if (chunk_header->total_sz !=                sparse_header->chunk_hdr_sz) {                log(error) << bogus chunk size for chunk type crc32 total_sz err chunk_sz;            data += chunk_data_sz;            break;        default:            log(info) << __func__ << : unknown chunk type: 原文标题:稀疏镜像在openharmony上的应用
文章出处:【微信公众号:openatom openharmony】欢迎添加关注!文章转载请注明出处。

5G电磁辐射对人体有危害吗?
2022全球印制电路板行业专利申请概况分析
移远通信出席2023中国企业家博鳌论坛,以技术创新引领产业数智化变革
iphone8什么时候上市?iphone8最新消息:苹果全新产品曝光,将配合iphone8使用
2020可穿戴设备向“体育+医疗”转型
稀疏镜像在OpenHarmony上的应用
生物识别如何走进普通的市场
不间断电源UPS可以随时启用吗?
警用无人机和警务直升机哪个更好用
还在为硬盘容量有限烦恼吗?简单几招 让你的电脑C盘立刻瘦身60%
法国电信在中国数字化服务中的实践
安科瑞AHBC-CANB500汽车级CAN输出电流霍尔传感器
双电源主动改换开关的构造与作业原理及在高炉低压配电体系的运用
小米MIX2、iPhone8一决雌雄,小米MIX2携手四大特色来袭能否逆袭iPhone8成机皇?
涨知识~Windows/Mac上推荐的11款WMV播放器
计数、译码、显示综合实验
罗德与施瓦茨发布新型手持式微波频谱分析仪,RS Spectrum Rider FPH家族又添新成员
南大光电:ArF光刻胶原材料不存在依赖进口情况
城域网路由器网络层可靠性技术
eNet研究院发布“2019人工智能未来企业TOP100”榜单