在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

稀疏鏡像在 OpenHarmony 上的探索

電子發(fā)燒友開源社區(qū) ? 來(lái)源:未知 ? 2023-01-06 08:30 ? 次閱讀
一、稀疏鏡像升級(jí)背景
常用系統(tǒng)鏡像格式為原始鏡像,即RAW格式。鏡像體積比較大,在燒錄固件或者升級(jí)固件時(shí)比較耗時(shí),而且在移動(dòng)設(shè)備升級(jí)過(guò)程時(shí)比較耗費(fèi)流量。為此,將原始鏡像用稀疏描述,可以大大的縮減鏡像體積,省時(shí)省流量。

二、稀疏鏡像原理
1. 稀疏鏡像概念
  • 原始鏡像:即raw image,完整的ext4分區(qū)鏡像,包含很多全零的無(wú)效填充區(qū)
  • 稀疏鏡像:即sparse image,將raw ext4進(jìn)行稀疏描述,因此尺寸比較小,制作目錄有多少文件就計(jì)算多少,沒(méi)有全零填充

2. 稀疏鏡像格式

稀疏鏡像數(shù)據(jù)格式:首先是sparse_header占用28byte,然后是12byte的chunk_header,同樣這chunk_header的類型決定了后面跟著的數(shù)據(jù),如果讀到數(shù)據(jù)是0xCAC1意味著后面是本身的raw_data,如果是0xCAC3,則后面num為0,接著再0xCAC2意味著后面填充4byte的內(nèi)容。

三、實(shí)現(xiàn)稀疏鏡像升級(jí)方案
1. 稀疏鏡像燒錄
生成稀疏格式鏡像,有2種方法可以生成稀疏鏡像:
修改文件build/ohos_var.gni中,sparse_image=true

編譯命令增加--sparse-image字段,
如./build.sh --product-name=xxx --sparse-image

增加稀疏格式轉(zhuǎn)換工具
在目錄build/ohos/images/mkimage中增加文件img2simg,該工具用于編譯完成后將raw鏡像轉(zhuǎn)換為sparse格式,并設(shè)置權(quán)限為777。

編譯后的鏡像對(duì)比

編譯出的鏡像格式為sparse格式,鏡像大小相比raw格式明顯變小。燒錄稀疏鏡像方法和燒錄原始鏡像方法一致。稀疏鏡像本身是不能直接掛載的,在燒錄過(guò)程中通過(guò)uboot將稀疏格式鏡,還原為原始鏡像,然后寫到磁盤中,系統(tǒng)啟動(dòng)后可掛載對(duì)應(yīng)的鏡像。

2. 稀疏鏡像OTA升級(jí)
OTA升級(jí)的升級(jí)包采用稀疏鏡像制作。

(1)修改升級(jí)包制作工具
官方升級(jí)包工具不支持生成稀疏鏡像的升級(jí)包,修改升級(jí)包工具,生成稀疏格式的升級(jí)包。
.aseupdatepackaging_toolsimage_class.py
按照上圖所示注釋代碼

(2)生成稀疏鏡像升級(jí)包
和全量鏡像升級(jí)包制作方法一致。

(3)適配updater組件中稀疏鏡像功能
增加寫稀疏鏡像分支
.aseupdateupdaterservicesapplypatchdata_writer.cpp
寫數(shù)據(jù)函數(shù)CreateDataWriter增加寫稀疏鏡像分支
case WRITE_SPARSE:{std::make_unique(partitionName));return std::move(writer);}
增加稀疏鏡像類聲明
.aseupdateupdaterservicesapplypatch
aw_writer.h
增加稀疏鏡像類聲明及相關(guān)變量定義
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    0xCAC4typedef 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_;};
增加稀疏鏡像類實(shí)現(xiàn)
.aseupdateupdaterservicesapplypatch
aw_writer.cpp
增加稀疏鏡像類實(shí)現(xiàn)及相關(guān)變量定義,原有代碼不變
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;
}

本文介紹了OpenHarmony系統(tǒng)中實(shí)現(xiàn)稀疏鏡像升級(jí)的方法,理解稀疏鏡像原理及稀疏鏡像還原方法可以快速在自己的系統(tǒng)中應(yīng)用稀疏鏡像升級(jí),提高系統(tǒng)升級(jí)速度。


更多熱點(diǎn)文章閱讀
  • DevEco Studio新特性分享-跨語(yǔ)言調(diào)試,讓調(diào)試更便捷高效
  • 基于 OpenHarmony 的智聯(lián)北斗海防系統(tǒng)
  • 玩轉(zhuǎn)OpenHarmony智能家居:如何實(shí)現(xiàn)樹莓派“碰一碰”設(shè)備控制
  • 玩轉(zhuǎn)OpenHarmony社交場(chǎng)景:即時(shí)通訊平臺(tái)
  • HarmonyOS多媒體框架介紹


提示:本文由電子發(fā)燒友社區(qū)發(fā)布,轉(zhuǎn)載請(qǐng)注明以上來(lái)源。如需社區(qū)合作及入群交流,請(qǐng)?zhí)砑游⑿臙EFans0806,或者發(fā)郵箱liuyong@huaqiu.com。


原文標(biāo)題:稀疏鏡像在 OpenHarmony 上的探索

文章出處:【微信公眾號(hào):電子發(fā)燒友開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 電子發(fā)燒友
    +關(guān)注

    關(guān)注

    33

    文章

    556

    瀏覽量

    33113
  • 開源社區(qū)
    +關(guān)注

    關(guān)注

    0

    文章

    94

    瀏覽量

    487

原文標(biāo)題:稀疏鏡像在 OpenHarmony 上的探索

文章出處:【微信號(hào):HarmonyOS_Community,微信公眾號(hào):電子發(fā)燒友開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Flexusx 實(shí)例與 Harbor 私有鏡像倉(cāng)庫(kù)的完美結(jié)合

    前言 華為云 828 企業(yè)云節(jié),F(xiàn)lexus X 實(shí)例攜手 Harbor 私有鏡像倉(cāng)庫(kù),共創(chuàng)云安全高效新生態(tài)!Flexus X 以其卓越性能與穩(wěn)定性,為 Harbor 提供了理想的運(yùn)行環(huán)境
    的頭像 發(fā)表于 01-22 18:04 ?110次閱讀
    Flexusx 實(shí)例與 Harbor 私有<b class='flag-5'>鏡像</b>倉(cāng)庫(kù)的完美結(jié)合

    Docker-鏡像的分層-busybox鏡像制作

    目錄 知識(shí)點(diǎn)1:鏡像的分層 示例:進(jìn)入 docker hub查看Jenkins的Dockerfile 知識(shí)點(diǎn)2:base鏡像 知識(shí)點(diǎn)3:scratch鏡像 scratch 鏡像是什么?
    的頭像 發(fā)表于 01-15 10:44 ?146次閱讀
    Docker-<b class='flag-5'>鏡像</b>的分層-busybox<b class='flag-5'>鏡像</b>制作

    OpenHarmony通過(guò)掛載鏡像來(lái)修改鏡像內(nèi)容,RK3566鴻蒙開發(fā)板演示

    OpenHarmony通過(guò)掛載鏡像來(lái)修改鏡像內(nèi)容的教程,提高修改鏡像內(nèi)容效率!
    的頭像 發(fā)表于 01-03 14:21 ?189次閱讀
    <b class='flag-5'>OpenHarmony</b>通過(guò)掛載<b class='flag-5'>鏡像</b>來(lái)修改<b class='flag-5'>鏡像</b>內(nèi)容,RK3566鴻蒙開發(fā)板演示

    OpenHarmony源碼編譯后燒錄鏡像教程,RK3566鴻蒙開發(fā)板演示

    本文介紹瑞芯微主板/開發(fā)板編譯OpenHarmony源碼后燒錄鏡像的教程,觸覺(jué)智能Purple Pi OH鴻蒙開發(fā)板演示。搭載了瑞芯微RK3566四核處理器,樹莓派卡片電腦設(shè)計(jì),支持開源鴻蒙OpenHarmony3.2-5.0系
    的頭像 發(fā)表于 12-30 10:08 ?202次閱讀
    <b class='flag-5'>OpenHarmony</b>源碼編譯后燒錄<b class='flag-5'>鏡像</b>教程,RK3566鴻蒙開發(fā)板演示

    dayu200 rk3568 openharmony5.0 sim卡 通話服務(wù)

    想請(qǐng)問(wèn)一下有人在dayu200 rk3568插過(guò)sim卡并且成功完成過(guò)通話服務(wù)嗎? 我現(xiàn)在在dayu200燒錄了openHarmony release 5.0.0版本的鏡像,在上面
    發(fā)表于 12-26 16:52

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程介紹之燒寫所需鏡像

    USB OTG燒寫所需鏡像在:ELF 1開發(fā)板資料包\\06-常用工具\(yùn)\06-4 燒寫工具\(yùn)\OTG燒寫\\mfgtools\\Profiles\\Linux\\OS Firmware
    發(fā)表于 12-21 09:25

    飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程介紹之燒寫所需鏡像

    USB OTG燒寫所需鏡像在:ELF 1開發(fā)板資料包\\06-常用工具\(yùn)\06-4 燒寫工具\(yùn)\OTG燒寫\\mfgtools\\Profiles\\Linux\\OS Firmware
    發(fā)表于 12-20 09:05

    星光璀璨,聆聽 OpenHarmony 貢獻(xiàn)者之聲

    在第三屆開放原子開源基金會(huì)OpenHarmony技術(shù)大會(huì)上, 我們滿懷敬意地對(duì)取得優(yōu)秀成果的星光OpenHarmony技術(shù)俱樂(lè)部、星光導(dǎo)師、星光貢獻(xiàn)者、星光活動(dòng)進(jìn)行了致謝。 他們不僅是技術(shù)的探索
    發(fā)表于 10-28 17:09

    [2K300適配OpenharmonyV4.1]根文件系統(tǒng)制作請(qǐng)教

    官方你好,我這邊需要適配OpenharmonyV4.1,但是目前網(wǎng)上找不到2K300的開源資料,我嘗試使用2K500開源資料搭建開發(fā)環(huán)境,目前已成功編譯出對(duì)應(yīng)鏡像,但是我想將OpenHarmony
    發(fā)表于 09-11 11:18

    河南大學(xué)OpenHarmony技術(shù)俱樂(lè)部正式揭牌成立

    8月30日,由OpenAtom OpenHarmony(以下簡(jiǎn)稱“OpenHarmony”)項(xiàng)目群技術(shù)指導(dǎo)委員會(huì)與河南大學(xué)共同舉辦的“河南大學(xué)OpenHarmony技術(shù)俱樂(lè)部成立大會(huì)”在鄭州校區(qū)友蘭
    的頭像 發(fā)表于 09-03 16:12 ?488次閱讀
    河南大學(xué)<b class='flag-5'>OpenHarmony</b>技術(shù)俱樂(lè)部正式揭牌成立

    第二屆大會(huì)回顧第25期 | OpenHarmony的Python設(shè)備應(yīng)用開發(fā)

    Python以其簡(jiǎn)單、易學(xué)和功能強(qiáng)大而聞名,有著廣泛的用戶群體。采用Python開發(fā)有助于降低OpenHarmony的學(xué)習(xí)門檻。如何在OpenHarmony用Python開發(fā)設(shè)備應(yīng)用,有哪些關(guān)鍵技術(shù)?電
    的頭像 發(fā)表于 08-27 11:53 ?792次閱讀
    第二屆大會(huì)回顧第25期 | <b class='flag-5'>OpenHarmony</b><b class='flag-5'>上</b>的Python設(shè)備應(yīng)用開發(fā)

    鴻蒙OpenHarmony南向/北向快速開發(fā)教程-迅為RK3568開發(fā)板

    4.1學(xué)習(xí)之旅了嗎?快來(lái)加入我們,一起探索鴻蒙4.1系統(tǒng)的無(wú)限魅力吧! 【北京迅為】OpenHarmony學(xué)習(xí)開發(fā)系列教程(第1期 北向基礎(chǔ)篇一) P0_先導(dǎo)課 P1_OpenHarmony系統(tǒng)概述
    發(fā)表于 07-23 10:44

    【飛凌嵌入式OK527N-C開發(fā)板體驗(yàn)】- 3. 打包鏡像以及燒錄

    只想更新boot或者設(shè)備樹等則勾選單或多分區(qū)下載,并勾選需要下載的部分。 內(nèi)核鏡像在BOOT分區(qū),設(shè)備樹和uboot在BOOT-RESOURCE分區(qū) 查看燒錄的是不是自己編譯的版本,進(jìn)入系統(tǒng)后輸入如下
    發(fā)表于 07-11 21:27

    【飛凌嵌入式OK527N-C開發(fā)板體驗(yàn)】-打包鏡像以及燒錄

    只想更新boot或者設(shè)備樹等則勾選單或多分區(qū)下載,并勾選需要下載的部分。 內(nèi)核鏡像在BOOT分區(qū),設(shè)備樹和uboot在BOOT-RESOURCE分區(qū) 查看燒錄的是不是自己編譯的版本,進(jìn)入系統(tǒng)后輸入如下
    發(fā)表于 07-05 23:15

    【五】Purple Pi OH開發(fā)板帶你7天入門OpenHarmony

    在完成了PurplePiOH大部分的接口測(cè)試之后,緊接著就是一個(gè)充滿挑戰(zhàn)的任務(wù)——利用SDK來(lái)編譯生成我們自己的鏡像文件。通過(guò)這一過(guò)程,不僅能夠讓你獲得一個(gè)可在真實(shí)硬件運(yùn)行的系統(tǒng)鏡像,更重要的是,它讓你對(duì)
    的頭像 發(fā)表于 03-07 08:31 ?532次閱讀
    【五】Purple Pi OH開發(fā)板帶你7天入門<b class='flag-5'>OpenHarmony</b>
    主站蜘蛛池模板: 亚洲成a人片在线观看www | 亚洲午夜精品久久久久久人妖 | 四虎永久影院永久影库 | 国产精品久久国产三级国不卡顿 | 欧美猛交喷潮在线播放 | 国产一区中文字幕在线观看 | 亚洲伊人久久大香线蕉啊 | 岛国午夜 | xx在线观看 | 久久国产精品免费观看 | 国内自拍网红在综合图区 | 思思99re66在线精品免费观看 | 亚洲精品美女久久久aaa | 欧美一区二区三区综合色视频 | 亚洲va国产日韩欧美精品色婷婷 | 狠狠色狠狠色综合日日小蛇 | 久草资源网 | 国产成人精品三级在线 | 真人实干一级毛片aa免费 | 性做久久久久久久免费看 | 午夜看一级特黄a大片黑 | 美国69bj | 免费看污视频的网站 | 四虎最新永久在线精品免费 | 综合久色| 高清毛片aaaaaaaaa片 | 黄色网址你懂得 | 国产又色又爽又黄的网站在线一级 | 91精品欧美激情在线播放 | 日本一卡二卡≡卡四卡精品 | 黄页网址免费观看18网站 | 又粗又大又爽又色又过瘾视频 | 免费手机黄色网址 | 天堂中文在线资源库用 | 欧美a在线播放 | 日本不卡视频免费的 | 久久国产免费观看精品 | 国产三级精品播放 | 欧美黄色性 | 天天做天天爱夜夜大爽完整 | 天堂网www天堂在线网 |