開源項目 OpenHarmony是每個人的 OpenHarmony
![b486eddc-a85d-11ed-bfe3-dac502259ad0.jpg](https://file1.elecfans.com//web2/M00/98/68/wKgZomTnXfuAHJ4CAADWPU3bJo0919.jpg)
陳甲印
鴻湖萬聯高級技術專家
一、稀疏鏡像升級背景
常用系統鏡像格式為原始鏡像,即RAW格式。鏡像體積比較大,在燒錄固件或者升級固件時比較耗時,而且在移動設備升級過程時比較耗費流量。為此,將原始鏡像用稀疏描述,可以大大地縮減鏡像體積,省時省流量。二、稀疏鏡像原理
1、稀疏鏡像的概念 原始鏡像:即raw image,完整的ext4分區鏡像,包含很多全零的無效填充區 稀疏鏡像:即sparse image,將raw ext4進行稀疏描述,因此尺寸比較小,制作目錄有多少文件就計算多少,沒有全零填充2、稀疏鏡像格式![b4ab0d66-a85d-11ed-bfe3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/68/wKgZomTnXfuARYqPAACSAjTHRg8904.png)
三、實現稀疏鏡像升級方案
版本基線:
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![b4c588c6-a85d-11ed-bfe3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/68/wKgZomTnXfuAf4koAACAL6cfdl0837.png)
![b4f0c1e4-a85d-11ed-bfe3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/68/wKgZomTnXfuAFX7eAALQo8wSU3w357.png)
![b514972c-a85d-11ed-bfe3-dac502259ad0.png](https://file1.elecfans.com//web2/M00/98/68/wKgZomTnXfuACbAXAAFLonooxrY822.png)
參考:
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增加稀疏鏡像類聲明及相關變量定義
typedefstructsparse_header{
uint32_tmagic; /* 0xed26ff3a */
uint16_tmajor_version;/* (0x1) - reject images with higher major versions */
uint16_tminor_version;/* (0x0) - allow images with higer minor versions */
uint16_tfile_hdr_sz; /* 28 bytes for first revision of the file format */
uint16_tchunk_hdr_sz; /* 12 bytes for first revision of the file format */
uint32_tblk_sz; /* block size in bytes, must be a multiple of 4 (4096) */
uint32_ttotal_blks;/* total blocks in the non-sparse output image */
uint32_ttotal_chunks; /* total chunks in the sparse input image */
uint32_timage_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;
#defineSPARSE_HEADER_MAGIC 0xed26ff3a
#defineCHUNK_TYPE_RAW 0xCAC1
#defineCHUNK_TYPE_FILL 0xCAC2
#defineCHUNK_TYPE_DONT_CARE 0xCAC3
#defineCHUNK_TYPE_CRC32 0xCAC4
typedefstructchunk_header{
uint16_tchunk_type;/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
uint16_treserved1;
uint32_tchunk_sz; /* in blocks in output image */
uint32_ttotal_sz; /* in bytes of chunk input file including chunk header and data */
} chunk_header_t;
classSparseWriter: publicDataWriter{
public:
virtualboolWrite(constuint8_t*addr, size_tlen, WriteModemode, conststd::string&partitionName);
explicitSparseWriter(conststd::stringpartitionName) : offset_(0), fd_(-1), partitionName_(partitionName) {}
virtual~SparseWriter()
{
offset_= 0;
if(fd_> 0) {
fsync(fd_);
close(fd_);
}
fd_= -1;
}
private:
intWriteInternal(intfd, constuint8_t*data, size_tlen, conststd::string&partitionName);
SparseWriter(constSparseWriter&) = delete;
constSparseWriter&operator=(constSparseWriter&) = delete;
off64_toffset_;
intfd_;
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;
}
}
UPDATER_CHECK_ONLY_RETURN(WriteInternal(fd_, addr, len, partitionName_) >= 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_ " << offset_;
/* Read and skip over sparse image header */
sparse_header = (sparse_header_t *)data;
data += sparse_header->file_hdr_sz;
if (sparse_header->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: " ?<< sparse_header->magic;
LOG(INFO) << "major_version: " << sparse_header->major_version;
LOG(INFO) << "minor_version: " << sparse_header->minor_version;
LOG(INFO) << "file_hdr_sz: " << sparse_header->file_hdr_sz;
LOG(INFO) << "chunk_hdr_sz: " << sparse_header->chunk_hdr_sz;
LOG(INFO) << "blk_sz: " << sparse_header->blk_sz;
LOG(INFO) << "total_blks: " << sparse_header->total_blks;
LOG(INFO) << "total_chunks: " << sparse_header->total_chunks;
LOG(INFO) << "Flashing Sparse Image";
blk = 0;
for (chunk = 0; chunk < sparse_header->total_chunks; chunk++) {
/* Read and skip over chunk header */
chunk_header = (chunk_header_t *)data;
data += sizeof(chunk_header_t);
if (chunk_header->chunk_type != CHUNK_TYPE_RAW)
{
LOG(INFO) << "=== Chunk Header ===";
LOG(INFO) << "chunk_type: " << chunk_header->chunk_type;
LOG(INFO) << "chunk_sz: " << chunk_header->chunk_sz;
LOG(INFO) << "total_sz: " << chunk_header->total_sz;
}
if (sparse_header->chunk_hdr_sz > 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) << "Bogus chunk size for chunk type Raw";
return -1;
}
if (blk + blkcnt > 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) << "SparseWriter: failed to write data of len ";
return -1;
}
total_bytes = total_bytes + blkcnt * block_size;
blks = written / block_size;
blk += blks;
bytes_written += blkcnt * block_size;
total_blocks += chunk_header->chunk_sz;
data += chunk_data_sz;
break;
case CHUNK_TYPE_FILL:
if (chunk_header->total_sz !=
(sparse_header->chunk_hdr_sz + sizeof(uint32_t))) {
LOG(ERROR) << "Bogus chunk size for chunk type FILL total_sz err " << chunk_header->total_sz << "
";
return -1;
}
ret = posix_memalign (&membuf, 64,
ROUNDUP(
block_size * fill_buf_num_blks,
64));
if (ret) {
LOG(ERROR) << "posix_memalign:" << strerror (errno);
return -1;
}
fill_buf = (uint32_t *)membuf;
if (!fill_buf) {
LOG(ERROR) << "Malloc failed for: CHUNK_TYPE_FILL";
return -1;
}
fill_val = *(uint32_t *)data;
data = data + sizeof(uint32_t);
for (i = 0;
i < (block_size * fill_buf_num_blks /
sizeof(fill_val));
i++)
fill_buf[i] = fill_val;
if (blk + blkcnt > 0 + block_count) {
LOG(ERROR) << "Request would exceed partition size!";
return -1;
}
for (i = 0; i < blkcnt;) {
j = blkcnt - i;
if (j > fill_buf_num_blks)
j = fill_buf_num_blks;
addr_offset = blk * block_size;
ret = lseek64(fd, offset_ + addr_offset, SEEK_SET);
if (ret < 0) {
LOG(ERROR) << "failed to lseek file to " << addr_offset << " error=" << strerror(errno);
return -1;
}
written = write(fd, fill_buf, j * block_size);
if (written < 0) {
LOG(ERROR) << "SparseWriter: failed to write data of len ";
return -1;
}
total_bytes = total_bytes + j * block_size;
blks = written / block_size;
if (blks < j) {
LOG(ERROR) << "Write failed, block";
free(fill_buf);
return -1;
}
blk += blks;
i += j;
}
bytes_written += blkcnt * block_size;
total_blocks += chunk_data_sz / sparse_header->blk_sz;
free(fill_buf);
break;
case CHUNK_TYPE_DONT_CARE:
blk += blkcnt;
total_blocks += chunk_header->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_header->total_sz;
return -1;
}
total_blocks += chunk_header->chunk_sz;
data += chunk_data_sz;
break;
default:
LOG(INFO) << __func__ << ": Unknown chunk type: " << chunk_header->chunk_type;
return -1;
}
}
LOG(INFO) << "Wrote "<< chunk <<"blocks, expected to write " << sparse_header->total_blks << "blocks
";
LOG(INFO) << "........ wrote "<< bytes_written <<"bytes to " << partitionName << "
";
LOG(INFO) << "total_bytes=" << total_bytes;
return 0;
}
3、驗證稀疏鏡像升級(1)拷貝升級包將制作的稀疏鏡像升級包通過HDC工具推進系統data目錄,并修改文件名為updater.zip,路徑如下:/data/updater/updater.zip(2)啟動升級系統啟動后,在命令行工具輸入如下命令啟動升級reboot updater:--update_package=/data/updater/updater.zip輸入命令后,系統重啟,進入升級頁面,等待升級完成。
本文介紹了OpenHarmony系統中實現稀疏鏡像升級的方法,理解稀疏鏡像原理及稀疏鏡像還原方法可以快速在自己的系統中應用稀疏鏡像升級,提高系統升級速度。
原文標題:稀疏鏡像在OpenHarmony上的應用
文章出處:【微信公眾號:OpenAtom OpenHarmony】歡迎添加關注!文章轉載請注明出處。
-
鴻蒙
+關注
關注
57文章
2392瀏覽量
43059 -
OpenHarmony
+關注
關注
25文章
3747瀏覽量
16594
原文標題:稀疏鏡像在OpenHarmony上的應用
文章出處:【微信號:gh_e4f28cfa3159,微信公眾號:OpenAtom OpenHarmony】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
Flexusx 實例與 Harbor 私有鏡像倉庫的完美結合
![Flexusx 實例與 Harbor 私有<b class='flag-5'>鏡像</b>倉庫的完美結合](https://file1.elecfans.com//web3/M00/04/96/wKgZO2d2Km6ANkf-AAEA43MSbXE820.png)
Docker-鏡像的分層-busybox鏡像制作
![Docker-<b class='flag-5'>鏡像</b>的分層-busybox<b class='flag-5'>鏡像</b>制作](https://file1.elecfans.com/web3/M00/06/0F/wKgZO2eHIVWABdMXAAAXs32FF8s788.png)
華為云 X 實例的鏡像管理詳解
![華為云 X 實例的<b class='flag-5'>鏡像</b>管理詳解](https://file1.elecfans.com//web3/M00/05/29/wKgZO2d87WCAUbD8AACKsQT93Ao991.png)
Dockerfile鏡像制作與Docker-Compose容器編排
![Dockerfile<b class='flag-5'>鏡像</b>制作與Docker-Compose容器編排](https://file1.elecfans.com/web3/M00/05/19/wKgZO2d8mWeAPOtdAAArBZgZf3c712.png)
OpenHarmony源碼編譯后燒錄鏡像教程,RK3566鴻蒙開發板演示
![<b class='flag-5'>OpenHarmony</b>源碼編譯后燒錄<b class='flag-5'>鏡像</b>教程,RK3566鴻蒙開發板演示](https://file1.elecfans.com/web3/M00/04/41/wKgZO2dyAH2AFFx6AAB2FN45Lh8124.png)
dayu200 rk3568 openharmony5.0 sim卡 通話服務
嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程介紹之燒寫所需鏡像
飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程介紹之燒寫所需鏡像
[2K300適配OpenharmonyV4.1]根文件系統制作請教
第二屆大會回顧第25期 | OpenHarmony上的Python設備應用開發
![第二屆大會回顧第25期 | <b class='flag-5'>OpenHarmony</b><b class='flag-5'>上</b>的Python設備應用開發](https://file1.elecfans.com/web2/M00/04/4E/wKgZombNTbKAGXSVAAARd6jESHY243.jpg)
鴻蒙OpenHarmony南向/北向快速開發教程-迅為RK3568開發板
【飛凌嵌入式OK527N-C開發板體驗】- 3. 打包鏡像以及燒錄
【飛凌嵌入式OK527N-C開發板體驗】-打包鏡像以及燒錄
【五】Purple Pi OH開發板帶你7天入門OpenHarmony
![【五】Purple Pi OH開發板帶你7天入門<b class='flag-5'>OpenHarmony</b>](https://file1.elecfans.com/web2/M00/8F/50/wKgZomTMciWAD54NAABOGP2pQZY452.png)
評論