在嵌入式Linux開發(fā)領(lǐng)域,瑞芯微(Rockchip)平臺憑借其穩(wěn)定的性能和豐富的生態(tài)支持,被廣泛應(yīng)用于各類智能設(shè)備中。而設(shè)備的升級功能作為保障產(chǎn)品生命周期、優(yōu)化用戶體驗(yàn)的核心模塊,其開發(fā)質(zhì)量直接影響產(chǎn)品的市場競爭力。本文基于Rockchip Linux updateEngine升級方案官方文檔,系統(tǒng)梳理RK平臺升級開發(fā)的核心技術(shù)方案、實(shí)現(xiàn)流程及關(guān)鍵注意事項(xiàng),為開發(fā)工程師提供全面的實(shí)踐指引。

開始之前我們先看一下spi+pcie升級log:
root@linaro-alip:/# updateEngine --image_url=/userdata/update.img --misc=update --savepath=/userdata/update.img --reboot &[1] 3788root@linaro-alip:/# LOG_INFO: *** update_engine: V1.0.1-g***. LOG_INFO: Current Mode is 'A' system.LOG_INFO: start RK_ota_url url [/userdata/update.img] save path [/userdata/update.img].LOG_INFO: save image to /userdata/update.img.LOG_INFO: url = /userdata/update.img.LOG_INFO: [MiscUpdate:90] save path: /userdata/update.imgLOG_INFO: In A system, now upgrade B system.LOG_INFO: [RK_ota_set_partition:125] num [16]LOG_INFO: need update parameter.LOG_INFO: need update uboot_b.LOG_INFO: need update boot_b.LOG_INFO: need update system_b.LOG_INFO: start RK_ota_start.LOG_INFO: rk m_status =1.LOG_INFO: where the file is local.LOG_INFO:LOG_INFO: entry0: storage =512firmware_offset =192, firmware_size =6226506LOG_INFO: entry1: storage =2048firmware_offset =6226698, firmware_size =5079775818LOG_DEBUG: uiTag =57464b52.LOG_DEBUG: usSize =66.LOG_DEBUG: dwVersion =1000000.LOG_DEBUG: btMajor =1, btMinor =0, usSmall =00.LOG_DEBUG: dwBootOffset =66.LOG_DEBUG: dwBootSize =771c0.LOG_DEBUG: dwFWOffset =77226.LOG_DEBUG: dwFWSize =579004.LOG_DEBUG: tag =1178684242size =5738496machine_model = RK3588 manufacturer = RK3588 version =16777216item =5.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset =490214flash_offset = -1usespace =1size =127LOG_DEBUG: name = parameter file = parameter.txt offset =492262flash_offset =0usespace =1size =299LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset =102flash_offset = -1usespace =239size =487872LOG_DEBUG: name = uboot_a file = uboot.img offset =983782flash_offset =16384usespace =2560size =5242880LOG_DEBUG: name = uboot_b file = uboot.img offset =983782flash_offset =32768usespace =2560size =5242880LOG_INFO: new md5:7ea81bce7a98f59d890aafb5009c9f1bLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_ERROR: MD5Check is error of /userdata/update.imgLOG_ERROR: Md5Check update.img fwSize:6226474LOG_DEBUG: uiTag =57464b52.LOG_DEBUG: usSize =66.LOG_DEBUG: dwVersion =1000000.LOG_DEBUG: btMajor =1, btMinor =0, usSmall =00.LOG_DEBUG: dwBootOffset =66.LOG_DEBUG: dwBootSize =771c0.LOG_DEBUG: dwFWOffset =77226.LOG_DEBUG: dwFWSize =2ebfc804.LOG_DEBUG: tag =1178684242size =784320512machine_model = RK3588 manufacturer = RK3588 version =16777216item =10.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset =6716720flash_offset = -1usespace =1size =227LOG_DEBUG: name = parameter file = parameter.txt offset =6718768flash_offset =0usespace =1size =460LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset =102flash_offset = -1usespace =239size =487872LOG_DEBUG: name = misc file = misc.img offset =7210288flash_offset =16384usespace =24size =49152LOG_DEBUG: name = boot_a file = boot.img offset =7259440flash_offset =24576usespace =17525size =35889664LOG_DEBUG: name = boot_b file = boot.img offset =7259440flash_offset =155648usespace =17525size =35889664LOG_DEBUG: name = system_a file = rootfs.img offset =43150640flash_offset =352256usespace =2450944size =724566016LOG_DEBUG: name = system_b file = rootfs.img offset =43150640flash_offset =15032320usespace =2450944size =724566016LOG_DEBUG: name = oem file = oem.img offset =767716656flash_offset =29712384usespace =9182size =18804736LOG_DEBUG: name = userdata file = userdata.img offset =786521392flash_offset =29974528usespace =2204size =4513792LOG_INFO: new md5:1fdb493d189fec4198c90d2f27974e9cLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_ERROR: MD5Check is error of /userdata/update.imgLOG_ERROR: Md5Check update.img fwSize:784808490LOG_INFO: found rkimage_hdr.item[1].name = parameter mtd =0.LOG_INFO: found rkimage_hdr.item[6].name = parameter mtd =0.LOG_INFO: found rkimage_hdr.item[4].name = uboot_b mtd =0.LOG_INFO: found rkimage_hdr.item[10].name = boot_b mtd =0.LOG_INFO: found rkimage_hdr.item[12].name = system_b mtd =0.LOG_INFO: size more than4G, after adjusting is5019533312.LOG_INFO: Current device is not MTDLOG_INFO: now write parameter to /dev/block/by-name/gpt.LOG_INFO: ingore misc.LOG_INFO: now write uboot_b to /dev/block/by-name/uboot_b.LOG_INFO: update_cmd.flash_offset =0.LOG_INFO: flash_normal:200start.LOG_INFO: flash_normal:222, diff check for uboot_bLOG_WARN: Not a diff image, ret =80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/uboot_b.LOG_INFO: new md5:fdc69aec10a16d9d81b1a08b6ce8305dLOG_INFO: MD5Check is ok of /dev/block/by-name/uboot_bLOG_INFO: new md5:fdc69aec10a16d9d81b1a08b6ce8305dLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/uboot_b ok.LOG_INFO: now write boot_b to /dev/block/by-name/boot_b.LOG_INFO: update_cmd.flash_offset =0.LOG_INFO: flash_normal:200start.LOG_INFO: flash_normal:222, diff check for boot_bLOG_WARN: Not a diff image, ret =80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/boot_b.LOG_INFO: new md5:8ac9471d56990e08c4b1b9245f32a002LOG_INFO: MD5Check is ok of /dev/block/by-name/boot_bLOG_INFO: new md5:8ac9471d56990e08c4b1b9245f32a002LOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/boot_b ok.LOG_INFO: now write system_b to /dev/block/by-name/system_b.LOG_INFO: update_cmd.flash_offset =0.LOG_INFO: flash_normal:200start.LOG_INFO: flash_normal:222, diff check for system_bLOG_WARN: Not a diff image, ret =80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/system_b.LOG_INFO: new md5:ba696b83e3db9d44f45c2a5378762517LOG_INFO: MD5Check is ok of /dev/block/by-name/system_bLOG_INFO: new md5:ba696b83e3db9d44f45c2a5378762517LOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/system_b ok.LOG_INFO: RK_ota_start is ok!LOG_INFO: rk ota success.LOG_INFO: Current Mode is 'A' system.LOG_INFO: Current device is not MTDLOG_INFO: Current device is not MTDLOG_INFO: rk m_status =0.
一、升級方案核心架構(gòu):兩種啟動模式的選擇與對比
RK Linux平臺提供兩種核心升級啟動模式,分別適配不同的應(yīng)用場景,開發(fā)人員需根據(jù)產(chǎn)品需求靈活選擇。
(一)Recovery模式
Recovery模式通過在設(shè)備中劃分獨(dú)立的recovery分區(qū)(由kernel+resource+ramdisk組成)專門負(fù)責(zé)升級操作。其核心邏輯是通過u-boot讀取misc分區(qū)的引導(dǎo)參數(shù),判斷是否進(jìn)入Recovery系統(tǒng)執(zhí)行升級。
優(yōu)勢:升級完整性強(qiáng),即便過程中出現(xiàn)異常掉電等中斷情況,重啟后仍可繼續(xù)執(zhí)行升級,避免升級失敗導(dǎo)致設(shè)備故障。
劣勢:額外占用存儲分區(qū)資源,且升級必須重啟進(jìn)入Recovery模式,無法在正常系統(tǒng)(Normal系統(tǒng))中直接完成。
(二)Linux A/B模式
A/B模式采用雙固件設(shè)計(jì),設(shè)備中存儲兩套獨(dú)立的系統(tǒng)(slot A和slot B),可實(shí)現(xiàn)無縫切換。升級時無需進(jìn)入專用升級模式,在Normal系統(tǒng)中即可完成,重啟后直接切換到升級后的系統(tǒng)。
優(yōu)勢:升級過程無需切換至專用模式,用戶體驗(yàn)流暢;雙系統(tǒng)冗余設(shè)計(jì)可有效防止設(shè)備變磚,若當(dāng)前slot升級失敗或系統(tǒng)損壞,可自動切換至另一slot啟動;支持版本回滾,保障系統(tǒng)穩(wěn)定性。
劣勢:雙系統(tǒng)設(shè)計(jì)會增加Flash存儲占用率,對存儲資源要求更高。
兩種模式的核心差異還體現(xiàn)在代碼支持上:updateEngine工具同時支持兩種模式(RV1126/RV1109平臺專用),而rkupdate工具僅支持Recovery模式(適用于其他平臺)。
二、關(guān)鍵升級場景的實(shí)現(xiàn)流程
(一)基礎(chǔ)OTA升級:Recovery與A/B模式通用實(shí)現(xiàn)
OTA(Over-the-Air)升級是設(shè)備遠(yuǎn)程更新的核心方式,支持網(wǎng)絡(luò)下載升級和本地升級兩種形式,核心流程如下:
1.版本校驗(yàn):通過--version_url參數(shù)指定版本文件地址,與設(shè)備本地/etc/version中的版本號對比,判斷是否需要升級(該參數(shù)可缺省,缺省時跳過版本校驗(yàn))。
2.固件獲?。和ㄟ^--image_url參數(shù)指定遠(yuǎn)程固件地址或本地固件路徑,下載并保存至--savepath指定的目錄(默認(rèn)路徑為/tmp/update.img,建議自定義為/userdata/update.img以避免臨時目錄空間不足)。
3.分區(qū)升級:通過--partition參數(shù)指定待升級分區(qū)(建議使用0x3FFC00,不支持升級parameter和loader分區(qū))。
4.重啟生效:添加--reboot參數(shù),升級完成后自動重啟設(shè)備,Recovery模式重啟進(jìn)入Recovery系統(tǒng)完成最終升級,A/B模式重啟后切換至升級后的slot。
示例命令:
?網(wǎng)絡(luò)升級(A/B模式):
updateEngine --image_url=http://xxx/update_ota.img --update --reboot
?本地升級(Recovery模式):
updateEngine --image_url=/userdata/update.img --misc=update --reboot &
(二)差分升級:高效壓縮升級包
針對大尺寸固件升級時帶寬占用高、傳輸耗時久的問題,RK平臺支持差分升級方案,通過制作新舊固件的差分補(bǔ)丁包(update_diff.img),僅傳輸變化部分?jǐn)?shù)據(jù),大幅降低升級包體積。
1.前置依賴
?代碼依賴:需確保buildroot、external/recovery、tools目錄中包含差分升級相關(guān)補(bǔ)丁(如0001-ota-add-diff-firmware-script.patch等)。
?工具依賴:PC端需安裝bsdiff(sudo apt install bsdiff)和md5sum工具。
2.關(guān)鍵限制
?支持分區(qū):uboot/trust/kernel分區(qū)及squashfs格式的rootfs分區(qū)。
?不支持場景:ext2/ext4文件系統(tǒng)、mtd驅(qū)動的nand flash系統(tǒng)、加密分區(qū)及A/B模式。
?分區(qū)空間要求:存儲差分補(bǔ)丁包的分區(qū)(如userdata)空閑空間需不小于差分包(update_diff.img)與完整新rootfs.img的體積之和。
3.補(bǔ)丁包制作
通過工具腳本實(shí)現(xiàn)新舊固件的差分處理,命令如下:
cdtools/linux/Linux_Diff_Firmware/./mk-diff-ota.sh update_old.img update_new.img update_diff.img
生成的update_diff.img可直接通過updateEngine工具進(jìn)行OTA升級。
(三)SD卡啟動盤升級:離線升級方案
SD卡升級適用于設(shè)備無法聯(lián)網(wǎng)或首次燒錄固件的場景,需根據(jù)系統(tǒng)模式區(qū)分制作流程:
1.通用制作步驟
使用RK提供的SDDiskTool工具(Windows端路徑:toolswindowsSDDiskTool),選擇目標(biāo)SD卡、升級模式(SD啟動),加載對應(yīng)的固件文件,點(diǎn)擊“開始創(chuàng)建”生成啟動盤。成功后SD卡根目錄會生成sdupdate.img(由原始update.img重命名而來),將SD卡插入設(shè)備并重啟即可自動觸發(fā)升級。
2.模式專屬配置
?Recovery模式:直接使用update.img通過SDDiskTool制作啟動盤。
?A/B模式:需先通過SDK編譯生成update_sdcard.img(專門用于制作A/B模式啟動盤),用該鏡像制作啟動盤后,再將update_ab.img(完整雙分區(qū)固件)或update_ota.img(單slot固件)拷貝至SD卡,設(shè)備啟動時會優(yōu)先識別update_ab.img。
(四)恢復(fù)出廠設(shè)置:數(shù)據(jù)清除方案
恢復(fù)出廠設(shè)置的核心是格式化userdata分區(qū)(存儲用戶配置數(shù)據(jù)和應(yīng)用數(shù)據(jù)),回歸出廠默認(rèn)配置,實(shí)現(xiàn)方式如下:
1.觸發(fā)方式:通過硬件按鍵組合(RECOVERY + VOLUMEUP)觸發(fā),或執(zhí)行命令updateEngine --misc=wipe_userdata --reboot。
2.執(zhí)行流程:命令會向misc分區(qū)偏移4K位置寫入格式化指令,設(shè)備重啟后,S21mountall.sh腳本識別該指令并格式化userdata分區(qū)。
3.注意事項(xiàng):--reboot參數(shù)可缺省,缺省時需等待設(shè)備下次重啟才會執(zhí)行格式化。
三、開發(fā)配置與編譯關(guān)鍵步驟
(一)Recovery模式編譯配置
1.Buildroot配置(make menuconfig):
BR2_PACKAGE_RECOVERY=y # 開啟升級功能BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y # 使用updateEngine工具BR2_PACKAGE_RECOVERY_RECOVERYBIN=y # 開啟recovery bin文件BR2_PACKAGE_RECOVERY_UPDATEENGINEBIN=y # 編譯updateEngineBR2_PACKAGE_RECOVERY_NO_UI=y # 關(guān)閉UI(無屏設(shè)備必選)
2.編譯命令:
sourceenvsetup.sh# 選擇對應(yīng)平臺的rootfs和recovery配置make clean:recovery./build.sh# 新SDK可簡化為:./build.sh recovery && ./build.sh
(二)A/B模式編譯配置
1.Uboot配置(修改defconfig,如rk3308_defconfig):
CONFIG_AVB_LIBAVB=yCONFIG_AVB_LIBAVB_AB=yCONFIG_ANDROID_AB=y
2.Buildroot配置(make menuconfig):
BR2_PACKAGE_RECOVERY=yBR2_PACKAGE_RECOVERY_BOOTCONTROL=y # 開啟引導(dǎo)控制腳本BR2_PACKAGE_RECOVERY_RETRY= # 可選,引導(dǎo)模式為reset retry(默認(rèn)successful boot)BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y
3.分區(qū)表配置:在BoardConfig.mk中指定A/B模式分區(qū)表,如export RK_PARAMETER=parameter-ab-64bit.txt。
4.固件輸出:編譯后生成update_ab.img(燒錄用)、update_ota.img(OTA升級用)、update_sdcard.img(SD卡啟動用)。
(三)自定義分區(qū)升級
若需擴(kuò)展升級自定義分區(qū)(如factory分區(qū)),需修改external/recovery/update_engine/update.cpp中的UPDATE_CMD結(jié)構(gòu)體數(shù)組,添加自定義分區(qū)配置:
{"factory",false,false,0,0,0,"", flash_normal},
同時在--partition參數(shù)中設(shè)置對應(yīng)位值為1,確保升級工具識別該分區(qū)。
(四)SPI+PCIe方案專屬配置:patch添加說明
若采用SPI+PCIe存儲方案(區(qū)別于上述eMMC方案),需額外添加以下專屬patch以保障升級功能正常實(shí)現(xiàn),否則可能出現(xiàn)無法進(jìn)入系統(tǒng)的問題,具體操作及問題說明如下:
1.必備patch清單
?核心驅(qū)動適配patch:0001-spi-pcie-storage-adapt-update-engine.patch(適配SPI+PCIe存儲設(shè)備與updateEngine工具的通信驅(qū)動,解決存儲識別異常問題)
?分區(qū)管理優(yōu)化patch:0002-spi-pcie-partition-manager-enhance.patch(優(yōu)化SPI+PCIe方案下的分區(qū)讀寫邏輯,提升升級過程中數(shù)據(jù)傳輸穩(wěn)定性)
?A/B模式根分區(qū)適配patch:修改u-boot/common/android_ab.c文件(解決SPI+PCIe方案下A/B模式啟動時根分區(qū)識別失敗問題),具體patch內(nèi)容如下:
--- a/u-boot/common/android_ab.c+++ b/u-boot/common/android_ab.cvoid ab_update_root_partition(void)/* Judge the partition device type. */switch (dev_desc->if_type) {case IF_TYPE_MMC:+ case IF_TYPE_SCSI: /* scsi 0: UFS */if (strstr(part_type, "ENV"))snprintf(root_part_dev, 64, "root=/dev/mmcblk0p%d", part_num);else if (strstr(part_type, "EFI"))void ab_update_root_partition(void)break;default:printf("%s: Not found part type, failed to set root part device.n", __func__);+ ab_update_root_uuid();+ printf("Unknown part type, set default 'root=' with UUID.n");return;}
2.未添加patch的報(bào)錯信息
若未添加上述A/B模式根分區(qū)適配patch,設(shè)備啟動時會因根分區(qū)識別失敗無法進(jìn)入系統(tǒng),具體錯誤日志如下:
[ 4.933965] nvme nvme0:8/0/0default/read/poll queues[ 4.940453] nvme0n1: p1 p2 p3 p4 p5 p6 p7 p8[ 4.940808]Waitingforroot device...
四、調(diào)試與問題排查
(一)日志查看
1.串口日志:在buildroot/output/rockchip_***/target目錄下創(chuàng)建隱藏文件.rkdebug,可在串口輸出Recovery模式升級日志。
2.文件日志:升級完成后,在設(shè)備userdata/recovery/log文件中查看詳細(xì)升級記錄,命令:cat userdata/recovery/log。
(二)常見問題解決
1.升級失敗:檢查分區(qū)空間是否充足(尤其是差分升級時的userdata分區(qū))、固件是否為對應(yīng)模式支持的格式(A/B模式需使用update_ota.img或update_ab.img)、--partition參數(shù)是否包含不支持的分區(qū)(如loader、parameter)。
2.A/B模式切換失敗:檢查misc分區(qū)中引導(dǎo)參數(shù)(偏移2K位置)是否正確,通過updateEngine --misc=display調(diào)試查看分區(qū)引導(dǎo)信息,確保slot優(yōu)先級和嘗試啟動次數(shù)配置合理。
3.SD卡升級無響應(yīng):確認(rèn)SD卡啟動盤制作正確(A/B模式需包含update_sdcard.img和對應(yīng)的升級固件)、SD卡是否正常識別、固件文件名是否為sdupdate.img。
五、工具與附錄支持
(一)固件打包工具
1.Windows平臺:toolswindowsAndroidToolrockdev,修改package-file文件指定需打包的鏡像,執(zhí)行mkupdate.bat生成update.img。
2.Linux平臺:tools/linux/Linux_Pack_Firmware/rockdev,修改package-file文件,執(zhí)行mkupdate.sh生成update.img。
(二)Misc分區(qū)關(guān)鍵說明
Misc分區(qū)為無文件系統(tǒng)分區(qū),用于存儲引導(dǎo)配置參數(shù),核心偏移地址功能如下:
?2K位置:存儲A/B模式分區(qū)引導(dǎo)信息(優(yōu)先級、啟動次數(shù)、啟動狀態(tài)等)。
?4K位置:存儲格式化命令(恢復(fù)出廠設(shè)置用)。
?16K位置:實(shí)現(xiàn)Recovery系統(tǒng)與Normal系統(tǒng)的通信。
結(jié)語
RK平臺的升級方案覆蓋了OTA遠(yuǎn)程升級、SD卡離線升級、差分升級等全場景需求,開發(fā)人員需根據(jù)產(chǎn)品的存儲資源、用戶體驗(yàn)要求選擇合適的啟動模式。在實(shí)際開發(fā)過程中,需重點(diǎn)關(guān)注編譯配置的完整性、分區(qū)空間的合理性及日志調(diào)試的有效性,同時遵循官方對分區(qū)升級的限制(如不支持loader和parameter分區(qū)升級),確保升級功能的穩(wěn)定性和可靠性。通過本文的梳理,希望能為RK平臺開發(fā)工程師提供清晰的升級開發(fā)路徑,助力高效完成產(chǎn)品升級模塊的設(shè)計(jì)與實(shí)現(xiàn)。
下期我們詳細(xì)分析ab系統(tǒng)下spi+pcie雙存儲方案升級的點(diǎn)點(diǎn)滴滴。
審核編輯 黃宇
-
嵌入式
+關(guān)注
關(guān)注
5192文章
20274瀏覽量
331697 -
Linux
+關(guān)注
關(guān)注
88文章
11681瀏覽量
218575
發(fā)布評論請先 登錄
一文讀懂UEFI系統(tǒng):從應(yīng)用場景到RK平臺開發(fā)全攻略
米爾RK3506核心板SDK重磅升級,解鎖三核A7實(shí)時控制新架構(gòu)
RK3576驅(qū)動高端顯控系統(tǒng)升級:多屏拼控與AI視覺融合解決方案
RK?平臺?DDR?測試終極指南:標(biāo)準(zhǔn)化步驟?+?全場景適配方案
瑞芯微 RK3588 平臺 Debian 系統(tǒng)開發(fā)案例與使用說明
PPEC Workbench 平臺拓?fù)淙?b class='flag-5'>覆蓋,滿足各類電源開發(fā)需求
360環(huán)視硬件平臺為什么推薦使用米爾RK3576開發(fā)板?
福田歐曼銀河新能源重卡引領(lǐng)全場景運(yùn)營升級
【HZ-RK3568開發(fā)板免費(fèi)體驗(yàn)】01 開箱+環(huán)境搭建+系統(tǒng)燒錄升級
鴻蒙5開發(fā)寶藏案例分享---折疊屏開發(fā)實(shí)踐
迅為RK3568開發(fā)板驅(qū)動指南GPIO子系統(tǒng)GPIO子系統(tǒng)API函數(shù)的引入
迅為RK3568驅(qū)動指南GPIO子系統(tǒng) GPIO操作函數(shù)實(shí)驗(yàn)
迅為RK3568開發(fā)板驅(qū)動指南GPIO子系統(tǒng)三級節(jié)點(diǎn)操作函數(shù)實(shí)驗(yàn)
技術(shù)分享|iTOP-RK3588開發(fā)板Ubuntu20系統(tǒng)旋轉(zhuǎn)屏幕方案
RK?平臺升級開發(fā):全場景方案與實(shí)踐指南,覆蓋常規(guī)系統(tǒng)和ab系統(tǒng)
評論