嵌入式Linux下使用 Plymouth 實現(xiàn)開機(jī)畫面示例

By Toradex秦海

1). 簡介

嵌入式 Linux 下傳統(tǒng)實現(xiàn) Splash Screen 的方式是通過替換 kernel 默認(rèn)的 TUX 小企鵝 logo 為定制的開機(jī)畫面圖片來實現(xiàn)嵌入式設(shè)備開機(jī)圖片历等,雖然比較成熟且可以保證開機(jī)畫面加載比較早,但是存在的問題首先是對嵌入式設(shè)備不同顯示接口的兼容性不好拴魄,另外每次修改適配都需要重新編譯內(nèi)核记某,維護(hù)起來不是很方便舌稀,然后就是只能支持靜態(tài)圖片無法支持動畫。基于上述原因寺董,使用專門的 Splash Screen 工具來實現(xiàn)開機(jī)畫面逐漸成為嵌入式設(shè)備的主流方向,本文就簡單演示使用 Plymouth 工具來實現(xiàn)動態(tài)開機(jī)畫面的示例刻剥。

本文所演示的平臺來自于Toradex?Verdin?iMX8MM ?嵌入式平臺遮咖,基于?NXP iMX8M Mini?系列?ARM?處理器,主要核心架構(gòu)為?Cortex-A53?造虏。

2).?硬件準(zhǔn)備

a).Verdin iMX8MM ARM核心版配合?Dahlia載板御吞,并通過 DSI-LVDS Adapter 連接?10inch LVDS 液晶顯示屏以及調(diào)試串口以便測試麦箍。

3).?關(guān)于 Plymouth

a). Plymouth 是一個實現(xiàn) Linux 啟動過程中開機(jī)畫面的工具軟件,其啟動的時間非常早陶珠,通過 initramfs 幫助可以在 Linux 內(nèi)核加載同時啟動挟裂,甚至要早于 Linux rootfs 文件系統(tǒng)掛載。Plymouth 可以方便的實現(xiàn)開關(guān)機(jī)圖片或者動畫揍诽。

b). 關(guān)于 Plymouth 更多詳細(xì)介紹以及源代碼請自行參考如下資料诀蓉。

./ Plymouth 官方頁面

Plymouth

./ Plymouth 源代碼

https://gitlab.freedesktop.org/plymouth/plymouth

./ Plymouth 深入配置使用說明

Plymouth - ArchWiki

4).?通過 Ycoto 環(huán)境配置 Plymouth 并編譯 Ycoto Linux BSP Image

a). 配置 Ycoto Project 編譯環(huán)境

./ 參考這里配置基本的 Ycoto Project 編譯環(huán)境

Build a Reference Image with Yocto Project/OpenEmbedded | Toradex Developer Center

./ 參考如下文章配置定制化 layer

通過Yocto Project定制嵌入式Y(jié)octo Linux鏡像

b). 在定制化 layer meta-customer-demos 下面添加 layer 配置文件

---------------------------------------

$ mkdir -p ../oe_core/layers/meta-customer-demos/conf

$ cd .../oe_core/layers/meta-customer-demos/conf

### create layer.conf file ###

# We have a conf and classes directory, append to BBPATH

BBPATH .= ":${LAYERDIR}"

# We have recipes-* directories, add to BBFILES

BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"

BBFILE_COLLECTIONS += "customer-demos"

BBFILE_PATTERN_customer-demos = "^${LAYERDIR}/"

BBFILE_PRIORITY_customer-demos = "24"

# Let us add layer-specific bbappends which are only applied when that

# layer is included in our configuration

BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bbappend' % layer \

???????????????for layer in BBFILE_COLLECTIONS.split())}"

# Add layer-specific bb files too

BBFILES += "${@' '.join('${LAYERDIR}/%s/recipes*/*/*.bb' % layer \

???????????????for layer in BBFILE_COLLECTIONS.split())}"

LAYERDEPENDS_customer-demos = " \

????core \

????yocto \

????openembedded-layer gnome-layer multimedia-layer networking-layer \

"

LAYERSERIES_COMPAT_customer-demos = "hardknott honister kirkstone"

---------------------------------------

c). 在定制化 layer meta-customer-demos 下面添加 Plymouth 相關(guān)配置文件

./ 增加 Plymouth bb file

---------------------------------------

$ cd .../oe_core/layers/meta-customer-demos/

$ mkdir -p recipes-core/plymouth

$ cd recipes-core/plymouth

### cteate plymouth_%.bbappend file ###

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI += " \

file://toradexlogo-white.png \

file://spinner.plymouth \

"

PACKAGECONFIG = "pango drm"

EXTRA_OECONF += "--with-udev --with-runtimedir=/run"

do_install:append () {

install -m 0644 ${WORKDIR}/toradexlogo-white.png ${D}${datadir}/plymouth/themes/spinner/watermark.png

install -m 0644 ${WORKDIR}/spinner.plymouth ${D}${datadir}/plymouth/themes/spinner/spinner.plymouth

}

---------------------------------------

./ 添加 Plymouth 使用的 theme 文件 和 background logo 圖片文件,這里使用的是一個配合屏幕分辨率的白色背景圖片暑脆,因此 spinner 圖標(biāo)會被遮蓋渠啤,實際使用可以根據(jù)需要修改圖片文件和 theme 配置。

---------------------------------------

$ mkdir files

$ cp .../toradexlogo-white.png?files

$ cd files

### cteate spinner theme file spinner.plymouth ###

[Plymouth Theme]

Name=Spinner

Description=Adoption of official Spinner Theme for Toradex.

ModuleName=two-step

[two-step]

Font=Cantarell 12

TitleFont=Cantarell Light 30

ImageDir=/usr/share/plymouth/themes/spinner

DialogHorizontalAlignment=.5

DialogVerticalAlignment=.382

TitleHorizontalAlignment=.5

TitleVerticalAlignment=.382

HorizontalAlignment=.5

VerticalAlignment=.7

WatermarkHorizontalAlignment=.5

WatermarkVerticalAlignment=.45

Transition=none

TransitionDuration=0.0

BackgroundStartColor=0x000000

BackgroundEndColor=0x000000

ProgressBarBackgroundColor=0x606060

ProgressBarForegroundColor=0xffffff

MessageBelowAnimation=true

---------------------------------------

d). 由于 Plymouth 是文件系統(tǒng)組件饵筑,通過 Linux kernel 加載完成后在使能systemd 來啟動埃篓,這樣就會導(dǎo)致比較大的延遲;為了盡可能使 Plymouth 在系統(tǒng)啟動過程中盡早啟動根资,可以添加包含 Plymouth 的 Initramfs 鏡像使得 Plymouth 在 Linux Kernel 加載過程中即同步啟動了架专。

./ 添加 Initramfs bb 定義以及相關(guān)文件,對應(yīng)需要 files 目錄下的相關(guān)文件請參考這里

---------------------------------------

$ cd .../oe_core/layers/meta-customer-demos/recipes-core

$ mkdir -p initramfs-framework/files

$ cd initramfs-framework

### cteate initramfs-framework_1.0.bbappend file ###

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI += "\

????file://plymouth \

????file://kmod \

????file://0001-Mount-run-with-tmpfs.patch \

????file://0002-only-scan-for-block-devices.patch \

"

PACKAGES:append = " \

????initramfs-module-plymouth \

????initramfs-module-kmod \

"

SUMMARY:initramfs-module-plymouth = "initramfs support for plymouth"

RDEPENDS:initramfs-module-plymouth = "${PN}-base plymouth ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd-udev-rules', '', d)}"

FILES:initramfs-module-plymouth = "/init.d/02-plymouth"

SUMMARY:initramfs-module-kmod = "initramfs support for loading kernel modules"

RDEPENDS:initramfs-module-kmod = "${PN}-base"

FILES:initramfs-module-kmod = "\

????/init.d/01-kmod \

????/etc/modules-load.d/* \

"

do_install:append() {

????install -m 0755 ${WORKDIR}/plymouth ${D}/init.d/02-plymouth

????install -m 0755 ${WORKDIR}/kmod ${D}/init.d/01-kmod

}

# Adding modules so plymouth can show the splash screen during boot

SRC_URI:append:mx8-nxp-bsp = " file://50-imx8-graphics.conf"

RDEPENDS:initramfs-module-kmod:append:mx8-nxp-bsp = " \

????kernel-module-display-connector \

????kernel-module-lontium-lt8912b \

"

do_install:append:mx8-nxp-bsp() {

????install -d ${D}/etc/modules-load.d/

????install -m 0755 ${WORKDIR}/50-imx8-graphics.conf ${D}/etc/modules-load.d/50-imx8-graphics.conf

}

---------------------------------------

./ 添加 initramfs image 定義文件

---------------------------------------

$ cd .../oe_core/layers/meta-customer-demos/recipes-core

$ mkdir images

$ cd images

### cteate initramfs-plymouth-splash-image.bb file ###

DESCRIPTION = "Toradex plymouth splash demo initramfs image"

PACKAGE_INSTALL = "initramfs-framework-base initramfs-module-udev \

????initramfs-module-rootfs initramfs-module-debug \

????initramfs-module-plymouth ${VIRTUAL-RUNTIME_base-utils} base-passwd \

????initramfs-module-kmod"

SYSTEMD_DEFAULT_TARGET = "initrd.target"

# Do not pollute the initrd image with rootfs features

IMAGE_FEATURES = "splash"

export IMAGE_BASENAME = "initramfs-plymouth-splash-image"

IMAGE_LINGUAS = ""

LICENSE = "MIT"

IMAGE_FSTYPES = "cpio.gz"

IMAGE_FSTYPES:remove = "wic wic.gz wic.bmap wic.vmdk wic.vdi ext4 ext4.gz teziimg"

IMAGE_CLASSES:remove = "image_type_torizon image_types_ostree image_types_ota image_repo_manifest license_image qemuboot"

# avoid circular dependencies

EXTRA_IMAGEDEPENDS = ""

inherit core-image nopackages

IMAGE_ROOTFS_SIZE = "8192"

# Users will often ask for extra space in their rootfs by setting this

# globally. ?Since this is a initramfs, we don't want to make it bigger

IMAGE_ROOTFS_EXTRA_SPACE = "0"

IMAGE_OVERHEAD_FACTOR = "1.0"

BAD_RECOMMENDATIONS += "busybox-syslog"

---------------------------------------

e). 由于增加了 initramfs image玄帕,就需要修改 distroboot 啟動文件 boot.scr 來調(diào)整啟動進(jìn)程部脚,這里通過修改 u-boot-distro-boot 文件來適配,對應(yīng)的 files 目錄下的文件完整內(nèi)容請參考這里

---------------------------------------

$ cd .../oe_core/layers/meta-customer-demos/

$ mkdir -p recipes-bsp/u-boot/files

$ cd recipes-bsp/u-boot

### cteate u-boot-distro-boot.bbappend file ###

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

SRC_URI:append = " \

??file://boot.cmd.in \

"

---------------------------------------

f). 另外裤纹,對于 Verdin iMX8M Mini委刘,由于顯示部分是通過 DSI-LVDS Bridge 來實現(xiàn)的,為了使得在 initramfs 階段就可以加載相關(guān)驅(qū)動鹰椒,需要修改 Linux Kernel 配置锡移,而對于其他 iMX8/iMX8X/iMX8MP 如果是原生 LVDS/HDMI 接口則無需修改。

---------------------------------------

$ cd .../oe_core/layers/meta-customer-demos/

$ mkdir -p recipes-kernel/linux/files

$ cd recipes-kernel/linux

### cteate linux-toradex%.bbappend file ###

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"

# Prevent the use of in-tree defconfig

unset KBUILD_DEFCONFIG

SRC_URI += "\

????file://defconfig \

????"

---------------------------------------

./ files 目錄下的完整 defconfig 文件請見這里漆际,主要修改了如下幾個驅(qū)動的配置

---------------------------------------

-CONFIG_DRM_PANEL_LVDS=m

+CONFIG_DRM_PANEL_LVDS=y

-CONFIG_DRM_SEC_MIPI_DSIM=m

+CONFIG_DRM_SEC_MIPI_DSIM=y

-CONFIG_DRM_TI_SN65DSI83=m

+CONFIG_DRM_TI_SN65DSI83=y

-CONFIG_DRM_IMX_SEC_DSIM=m

+CONFIG_DRM_IMX_SEC_DSIM=y

---------------------------------------

g). 最后配置完成的 meta-customer-demos 文件結(jié)構(gòu)如下

---------------------------------------

$ tree meta-customer-demos/

meta-customer-demos/

├── conf

│?? └── layer.conf

├── recipes-bsp

│?? └── u-boot

│?? ????├── files

│?? ????│?? └── boot.cmd.in

│?? ????└── u-boot-distro-boot.bbappend

├── recipes-core

│?? ├── images

│?? │?? ├── initramfs-ostree-torizon-image.bb

│?? │?? └── initramfs-plymouth-splash-image.bb

│?? ├── initramfs-framework

│?? │?? ├── files

│?? │?? │?? ├── 0001-Mount-run-with-tmpfs.patch

│?? │?? │?? ├── 0002-only-scan-for-block-devices.patch

│?? │?? │?? ├── 50-imx8-graphics.conf

│?? │?? │?? ├── kmod

│?? │?? │?? ├── plymouth

│?? │?? │?? └── rootfs

│?? │?? └── initramfs-framework_1.0.bbappend

│?? └── plymouth

│?? ????├── files

│?? ????│?? ├── spinner.plymouth

│?? ????│?? └── toradexlogo-white.png

│?? ????└── plymouth_%.bbappend

└── recipes-kernel

????└── linux

????????├── files

????????│?? └── defconfig

????????└── linux-toradex%.bbappend

13 directories, 17 files

---------------------------------------

h). 為了將 initramfs 集成到編譯生成的 Image 壓縮包內(nèi)淆珊,需要修改如下 image_type 配置文件

---------------------------------------

--- a/layers/meta-toradex-bsp-common/classes/image_type_tezi.bbclass

+++ b/layers/meta-toradex-bsp-common/classes/image_type_tezi.bbclass

@@ -8,7 +8,7 @@

?WKS_FILE_DEPENDS:append = " tezi-metadata virtual/dtb"

?DEPENDS += "${WKS_FILE_DEPENDS}"

?IMAGE_BOOT_FILES_REMOVE = "${@make_dtb_boot_files(d) if d.getVar('KERNEL_IMAGETYPE') == 'fitImage' else ''}"

-IMAGE_BOOT_FILES:append = " overlays.txt ${@'' if d.getVar('KERNEL_IMAGETYPE') == 'fitImage' else 'overlays/*;overlays/'}"

+IMAGE_BOOT_FILES:append = " overlays.txt initramfs-plymouth-splash-image-${MACHINE}.cpio.gz;initramfs-plymouth-splash-image.img ${@'' if d.getVar('KERNEL_IMAGETYPE') == 'fitImage' else 'overlays/*;overlays/'}"

?IMAGE_BOOT_FILES:remove = "${IMAGE_BOOT_FILES_REMOVE}"

?RM_WORK_EXCLUDE += "${PN}"

---------------------------------------

i). 修改 build/conf/bblayer.conf 文件添加相關(guān) layer

---------------------------------------

--- a/build/conf/bblayers.conf ?2023-03-30 11:13:22.946533642 +0800

+++ b/build/conf/bblayers.conf 2023-11-17 16:03:01.666129480 +0800

@@ -35,6 +35,7 @@

???${TOPDIR}/../layers/meta-freescale-distro \

???${TOPDIR}/../layers/meta-toradex-demos \

???${TOPDIR}/../layers/meta-qt5 \

+ ?${TOPDIR}/../layers/meta-customer-demos?\

???\

???\

???${TOPDIR}/../layers/meta-toradex-distro \

---------------------------------------

j). 修改 build/conf/local.conf 文件,增加 Plymouth 和 initramfs 相關(guān)定義

---------------------------------------

# add plymouth support

CORE_IMAGE_EXTRA_INSTALL += "plymouth"

INITRAMFS_IMAGE = "initramfs-plymouth-splash-image"

INITRAMFS_FSTYPES = "cpio.gz"

---------------------------------------

k). 重新編譯生成 Ycoto Linux BSP Image

---------------------------------------

$ MACHINE="verdin-imx8mm" PARALLEL_MAKE="-j 4" BB_NUMBER_THREADS="4" bitbake tdx-reference-multimedia-image

---------------------------------------

l). 參考這里的說明將上述修改下重新編譯生成的 Ycoto Linux Image 通過 Toradex Easy Installer 更新到 Verdin iMX8MM 模塊奸汇。

5). Plymouth Splash 部署測試

a). 安裝好上述編譯的 Image 后施符,參考這里說明配置合適的 Device-tree Overlay 文件來適配屏幕;然后配置如下 U-boot 環(huán)境變量來顯示 Splash擂找,且縮短加載時間

---------------------------------------

# setenv tdxargs ‘quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3’

# setenv bootdelay 0

# saveenv && reset

---------------------------------------

b). 為了保證 Plymouth Splash和 Qt Demo App切換更自然戳吝,且中間不會被 Weston Desktop 中斷,需要修改一下一些 Systemd Service 文件

---------------------------------------

--- a/lib/systemd/system/plymouth-quit.service

+++ b/lib/systemd/system/plymouth-quit.service

@@ -1,6 +1,6 @@

?[Unit]

?Description=Terminate Plymouth Boot Screen

-After=rc-local.service plymouth-start.service systemd-user-sessions.service

+After=rc-local.service plymouth-start.service systemd-user-sessions.service waylan

d-app-launch.service

?[Service]

?ExecStart=-/bin/plymouth quit --retain-splash

--- a/lib/systemd/system/serial-getty@.service

+++ b/lib/systemd/system/serial-getty@.service

@@ -12,7 +12,7 @@

?Documentation=man:agetty(8) man:systemd-getty-generator(8)

?Documentation=http://0pointer.de/blog/projects/serial-console.html

?BindsTo=dev-%i.device

-After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service getty

-pre.target

+After=dev-%i.device systemd-user-sessions.service getty-pre.target

?After=rc-local.service

?# If additional gettys are spawned during boot then we should make

--- a/lib/systemd/system/weston.service

+++ b/lib/systemd/system/weston.service

@@ -13,7 +13,7 @@

?After=systemd-user-sessions.service

?# If Plymouth is used, we want to start when it is on its way out.

-After=plymouth-quit-wait.service

+#After=plymouth-quit-wait.service

?# D-Bus is necessary for contacting logind. Logind is required.

?Wants=dbus.socket

--- a/etc/xdg/weston/weston.ini

+++ b/etc/xdg/weston/weston.ini

@@ -6,6 +6,7 @@

?repaint-window=16

?#enable-overlay-view=1

?modules=screen-share.so

+shell=kiosk-shell.so

?#[shell]

?#size=1920x1080

---------------------------------------

b). 最后部署完成的測試效果如下贯涎,實測從開機(jī)到出現(xiàn) Splash 畫面大約5秒听哭,另外 Plymouth splash 默認(rèn)除了支持開機(jī)畫面,在 reboot 重啟和 poweroff 關(guān)機(jī)的時候也會同樣顯示 splash 畫面


動畫演示如下

6). 總結(jié)

本文基于嵌入式 Linux 簡單演示了 Plymouth splash 開機(jī)畫面的部署和測試。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末欢唾,一起剝皮案震驚了整個濱河市且警,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌礁遣,老刑警劉巖斑芜,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異祟霍,居然都是意外死亡杏头,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門沸呐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來醇王,“玉大人,你說我怎么就攤上這事崭添≡⒚洌” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵呼渣,是天一觀的道長棘伴。 經(jīng)常有香客問我,道長屁置,這世上最難降的妖魔是什么焊夸? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蓝角,結(jié)果婚禮上阱穗,老公的妹妹穿的比我還像新娘。我一直安慰自己使鹅,他們只是感情好揪阶,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著患朱,像睡著了一般鲁僚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上麦乞,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音劝评,去河邊找鬼姐直。 笑死,一個胖子當(dāng)著我的面吹牛蒋畜,可吹牛的內(nèi)容都是我干的声畏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼插龄!你這毒婦竟也來了愿棋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤均牢,失蹤者是張志新(化名)和其女友劉穎糠雨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徘跪,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡甘邀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了垮庐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片松邪。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖哨查,靈堂內(nèi)的尸體忽然破棺而出逗抑,到底是詐尸還是另有隱情,我是刑警寧澤寒亥,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布邮府,位于F島的核電站,受9級特大地震影響护盈,放射性物質(zhì)發(fā)生泄漏挟纱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一腐宋、第九天 我趴在偏房一處隱蔽的房頂上張望紊服。 院中可真熱鬧,春花似錦胸竞、人聲如沸欺嗤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽煎饼。三九已至,卻和暖如春校赤,著一層夾襖步出監(jiān)牢的瞬間吆玖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工马篮, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留沾乘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓浑测,卻偏偏與公主長得像翅阵,于是被迫代替她去往敵國和親歪玲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容