Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Docs
提交
23d5f157
D
Docs
项目概览
OpenHarmony
/
Docs
大约 1 年 前同步成功
通知
159
Star
292
Fork
28
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
Docs
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
23d5f157
编写于
5月 06, 2022
作者:
O
openharmony_ci
提交者:
Gitee
5月 06, 2022
浏览文件
操作
浏览文件
下载
差异文件
!3714 【OpenHarmony开源贡献者计划2022】相关格式及表达问题
Merge pull request !3714 from king_he/master
上级
a0bd3776
fcd755fe
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
57 addition
and
60 deletion
+57
-60
zh-cn/device-dev/subsystems/subsys-boot-appspawn.md
zh-cn/device-dev/subsystems/subsys-boot-appspawn.md
+13
-14
zh-cn/device-dev/subsystems/subsys-boot-bootstrap.md
zh-cn/device-dev/subsystems/subsys-boot-bootstrap.md
+3
-3
zh-cn/device-dev/subsystems/subsys-boot-faqs.md
zh-cn/device-dev/subsystems/subsys-boot-faqs.md
+3
-3
zh-cn/device-dev/subsystems/subsys-boot-init.md
zh-cn/device-dev/subsystems/subsys-boot-init.md
+10
-10
zh-cn/device-dev/subsystems/subsys-boot-overview.md
zh-cn/device-dev/subsystems/subsys-boot-overview.md
+13
-15
zh-cn/device-dev/subsystems/subsys-boot-syspara.md
zh-cn/device-dev/subsystems/subsys-boot-syspara.md
+15
-15
未找到文件。
zh-cn/device-dev/subsystems/subsys-boot-appspawn.md
浏览文件 @
23d5f157
...
...
@@ -8,26 +8,25 @@ appspawn被init启动后,等待接收进程间消息,根据消息内容启
## 功能简介
-
安全控制 支持为app设置SELinux标签。
-
安全控制
<br
/>
支持为app设置SELinux标签。
-
应用进程控制
-
支持为app设置AccessToken。
-
支持重启前,appspawn停止后,可同时停止所有已孵化的app进程。
-
冷启动
支持应用通过aa命令冷启动应用。
-
冷启动
<br
/>
支持应用通过aa命令冷启动应用。
```
param set appspawn.cold.boot true // 打开冷启动
状态
param set appspawn.cold.boot true // 打开冷启动
开关
aa start -d 12345 -a $name -b $package -C
参考:
参考
命令
:
aa start -d 12345 -a ohos.acts.startup.sysparam.function.MainAbility -b ohos.acts.startup.sysparam.function -C
```
## 基本概念
appspawn注册的服务名称为“appspawn”
, appspawn 通过监听本地socket,接收来自客户端的请求消息。消息类型为AppProperty的结构体, 定义路径为:“base/startup/appspawn_standard/interfaces/innerkits/include/sclient_socket.h“
。
appspawn注册的服务名称为“appspawn”
。appspawn 通过监听本地socket,接收来自客户端的请求消息。消息类型为AppProperty的结构体,定义路径为:“base/startup/appspawn_standard/interfaces/innerkits/include/sclient_socket.h”
。
**表1**
字段说明
...
...
@@ -46,14 +45,14 @@ appspawn注册的服务名称为“appspawn”, appspawn 通过监听本地socke
## 开发指导
接口定义路径: “base/startup/appspawn_standard/interfaces/innerkits/include/client_socket.h
“
,表 2为接口说明。
接口定义路径: “base/startup/appspawn_standard/interfaces/innerkits/include/client_socket.h
”
,表 2为接口说明。
### 接口说明
**表2**
字段
说明
**表2**
接口
说明
|
字段
名 | 说明 |
|
接口
名 | 说明 |
| -------- | -------- |
| CreateClient | 创建client。 |
| CloseClient | 关闭client。 |
...
...
@@ -64,7 +63,7 @@ appspawn注册的服务名称为“appspawn”, appspawn 通过监听本地socke
## 开发实例
接口使用参考
方式
:
接口使用参考:
```
...
...
@@ -83,14 +82,14 @@ std::shared_ptr<AppSpawn::ClientSocket> clientSocket = std::make_unique<AppSpawn
// 读结果
int pid;
clientSocket->ReadSocketMessage((void *)&pid, sizeof(pid));
// 如果失败,返回pid
如果小于等于0,则错误,
否则返回应用的进程id
// 如果失败,返回pid
小于等于0;
否则返回应用的进程id
```
## 常见问题
### 冷启动失败
### 冷启动
应用
失败
**现象描述**
...
...
@@ -98,6 +97,6 @@ std::shared_ptr<AppSpawn::ClientSocket> clientSocket = std::make_unique<AppSpawn
**解决方法**
1.
确认是否打开冷启动设置
1.
确认是否打开冷启动设置
。
2.
确认冷启动命令是否正确
2.
确认冷启动命令是否正确
。
zh-cn/device-dev/subsystems/subsys-boot-bootstrap.md
浏览文件 @
23d5f157
# bootstrap服务启动组件
bootstrap服务启动组件实现了服务的自动初始化,即服务的初始化函数无需显式调用,而是将其使用宏定义的方式申明,就会在系统启动时自动被执行。实现原理是将服务启动的函数通过宏
申明之后,放在预定义好的zInit代码段中,系统启动的时候调用OHOS_SystemInit接口,
遍历该代码段并调用其中的函数。因此,需要在链接脚本中添加zInit段,并且在main函数里调用OHOS_SystemInit接口。
bootstrap服务启动组件实现了服务的自动初始化,即服务的初始化函数无需显式调用,而是将其使用宏定义的方式申明,就会在系统启动时自动被执行。实现原理是将服务启动的函数通过宏
定义的方式申明之后,放在预定义好的zInit代码段中,系统启动的时候调用OHOS_SystemInit接口
遍历该代码段并调用其中的函数。因此,需要在链接脚本中添加zInit段,并且在main函数里调用OHOS_SystemInit接口。
zInit段的添加可参考已有的Hi3861平台的链接脚本,文件路径为vendor/hisi/hi3861/hi3861/build/link/link.ld.S。
...
...
@@ -12,7 +12,7 @@ zInit段的添加可参考已有的Hi3861平台的链接脚本,文件路径为
## 接口说明
bootstrap服务
启动:
bootstrap服务
自动初始化宏如表1所述。
**表1**
主要的服务自动初始化宏
...
...
@@ -49,7 +49,7 @@ void AppFeatureInit(void) {
}
APP_FEATURE_INIT(AppFeatureInit);
// 日志
的
打印顺序为:
// 日志打印顺序为:
// Init System Service
// Init System Feature
// Init App Service
...
...
zh-cn/device-dev/subsystems/subsys-boot-faqs.md
浏览文件 @
23d5f157
...
...
@@ -28,7 +28,7 @@
**可能原因**
被init启动的服务都有一个叫做“importance”的属性(详见
[
第2章表3
](
../subsystems/subsys-boot-init.md
)
第二章节表3
描述)。
被init启动的服务都有一个叫做“importance”的属性(详见
[
第2章表3
](
../subsystems/subsys-boot-init.md
)
描述)。
-
当该属性为0时,表示若当前服务进程退出,init不需要重启单板。
...
...
@@ -38,9 +38,9 @@
**解决办法**
1.
需要
通过日志确认崩溃或报错退出的服务,并解决其崩溃/报错的问题,然后重新烧写镜像即可。
1.
通过日志确认崩溃或报错退出的服务,并解决其崩溃/报错的问题,然后重新烧写镜像即可。
2.
也可以将崩溃
/
报错退出的服务的“importance”属性改为0,然后重新烧写镜像,这样即使其退出,init也不会重启单板。
2.
也可以将崩溃
或
报错退出的服务的“importance”属性改为0,然后重新烧写镜像,这样即使其退出,init也不会重启单板。
## 参数正确的情况下调用SetParameter/GetParameter返回失败
...
...
zh-cn/device-dev/subsystems/subsys-boot-init.md
浏览文件 @
23d5f157
...
...
@@ -6,13 +6,13 @@ init启动引导组件负责在系统启动阶段启动关键服务进程。 若
-
init启动引导的配置文件
init启动引导组件配置文件包含了所有需要由init进程启动的系统关键服务的服务名、可执行文件路径、权限和其他信息
,
烧写单板后可在“/etc/“目录下找到,文件名称为init.cfg,采用json格式,文件大小目前限制在100KB以内。
init启动引导组件配置文件包含了所有需要由init进程启动的系统关键服务的服务名、可执行文件路径、权限和其他信息
。
烧写单板后可在“/etc/“目录下找到,文件名称为init.cfg,采用json格式,文件大小目前限制在100KB以内。
init进程启动后读取/etc/init.cfg,然后解析其json格式内容,并根据解析结果依次加载系统服务。
各模块需要配置或添加关键服务时,可以在对应模块的cfg文件进行配置
,
编译过程中会将配置后的文件拷贝到/system/etc/init目录下,单板中可在"/etc/init/"目录下查找到对应的cfg文件。
各模块需要配置或添加关键服务时,可以在对应模块的cfg文件进行配置
。
编译过程中会将配置后的文件拷贝到/system/etc/init目录下,单板中可在"/etc/init/"目录下查找到对应的cfg文件。
对于单板中/etc/init下存在的cfg文件,init进程会逐一解析
,
下面分别介绍一下init扫描cfg文件的规则和cfg文件内容的具体组成格式。
对于单板中/etc/init下存在的cfg文件,init进程会逐一解析
。
下面分别介绍一下init扫描cfg文件的规则和cfg文件内容的具体组成格式。
-
cfg文件扫描规则
...
...
@@ -44,7 +44,7 @@ init启动引导组件负责在系统启动阶段启动关键服务进程。 若
```
对于充电模式和升级模式下cfg的扫描此处不作详细说明,我们关注正常系统启动时init扫描cfg文件的规则。
1. 对于/etc/init.cfg文件,是应当最先解析,因此直接调用解析接口解析该文件。
2. 对于/etc/init目录(
note
:/etc是指向/system/etc的一个符号链接,可以把它们看作是等价的),init进程会遍历该目录下的文件,匹配文件的后缀名,匹配到cfg文件时就会调用解析接口对该文件进行解析。
2. 对于/etc/init目录(
注
:/etc是指向/system/etc的一个符号链接,可以把它们看作是等价的),init进程会遍历该目录下的文件,匹配文件的后缀名,匹配到cfg文件时就会调用解析接口对该文件进行解析。
3. init还会遍历/vendor/etc/init目录下的cfg文件并进行解析,这个目录下的cfg文件应当是与硬件平台相关的。
-
cfg文件的组成格式
...
...
@@ -141,11 +141,11 @@ init启动引导组件负责在系统启动阶段启动关键服务进程。 若
进程启动时,支持在配置文件中配置服务进程的绑核、优先级、MAC信息以及AccessToken信息。
- init提供修改\*.cfg配置文件,
为服务进程提供cpu绑核功能。
- init提供修改\*.cfg配置文件,
为服务进程提供优先级设置。
- init提供修改\*.cfg配置文件,
为服务提供MAC信息设置,即服务的SELinux标签。
- init提供修改\*.cfg配置文件,
为服务提供设置AccessToken, 为系统服务进程设置其分布式Capability能力(仅标准系统以上提供)。
- init提供修改\*.cfg配置文件,
为服务提供抑制机制。
- init提供修改\*.cfg配置文件,为服务进程提供cpu绑核功能。
- init提供修改\*.cfg配置文件,为服务进程提供优先级设置。
- init提供修改\*.cfg配置文件,为服务提供MAC信息设置,即服务的SELinux标签。
- init提供修改\*.cfg配置文件,为服务提供设置AccessToken, 为系统服务进程设置其分布式Capability能力(仅标准系统以上提供)。
- init提供修改\*.cfg配置文件,为服务提供抑制机制。
服务进程启动&回收能力增强配置,如下:
```
...
...
@@ -159,7 +159,7 @@ init启动引导组件负责在系统启动阶段启动关键服务进程。 若
"secon" : "u:r:distributedsche:s0" / 服务的SELinux标签, "u:r:distributedsche:s0"为要设置的SELinux标签信息
},
```
- init FD代持
(仅标准系统以上提供)
- init FD代持
(仅标准系统以上提供)
FD代持是按需启动的一个辅助扩展机制,按需启动进程可以保持退出前的fd状态句柄不丢失。按需启动进程退出前可将fd发送给init代持,再次启动后再从init获取fd。
...
...
zh-cn/device-dev/subsystems/subsys-boot-overview.md
浏览文件 @
23d5f157
# 启动恢复子系统概述
## 启动恢复子系统上下文
下图是启动子系统上下文结构图:
启动子系统上下文结构如下图所示。
**图1**
下图是启动子系统上下文结构图:
**图1**
启动子系统上下文结构
!
[
zh-cn_image_0000001217858866
](
figures/zh-cn_image_0000001217858866.png
)
...
...
@@ -15,7 +14,7 @@
2.
init进程启动后,会挂载tmpfs,procfs,创建基本的dev设备节点,提供最基本的根文件系统。
3.
init也会启动ueventd监听内核热插拔设备事件,为这些设备创建dev设备节点;
包括block设备各个分区设备
都是通过此事件创建。
3.
init也会启动ueventd监听内核热插拔设备事件,为这些设备创建dev设备节点;
各个分区设备(包括block设备)
都是通过此事件创建。
4.
init进程挂载block设备各个分区(system,vendor)后,开始扫描各个系统服务的init启动脚本,并拉起各个SA服务。
...
...
@@ -26,10 +25,10 @@
7.
由于应用都需要加载JS的运行环境,涉及大量准备工作,因此appspawn作为应用的孵化器,在接收到foundation里的应用启动请求时,可以直接孵化出应用进程,减少应用启动时间。
启动子系统内部
涉及
以下组件:
启动子系统内部
包含
以下组件:
-
init启动引导组件
init启动引导组件对应的进程为init进程,是内核完成初始化后启动的第一个用户态进程。init进程启动之后,读取init.cfg配置文件,根据解析结果,执行相应命令(见
[
第2章表2
](
../subsystems/subsys-boot-init.md
)
描述
)并依次启动各关键系统服务进程,在启动系统服务进程的同时设置其对应权限。
init启动引导组件对应的进程为init进程,是内核完成初始化后启动的第一个用户态进程。init进程启动之后,读取init.cfg配置文件,根据解析结果,执行相应命令(见
[
第2章表2
](
../subsystems/subsys-boot-init.md
)
)并依次启动各关键系统服务进程,在启动系统服务进程的同时设置其对应权限。
-
ueventd启动引导组件
ueventd负责监听内核设备驱动插拔的netlink事件,根据事件类型动态管理相应设备的dev节点。
...
...
@@ -38,7 +37,7 @@
负责接收
**用户程序框架**
的命令孵化应用进程,设置新进程的权限,并调用应用程序框架的入口函数。
-
bootstrap服务启动组件
提供了各服务和功能的启动入口标识。在
SAMGR
启动时,会调用bootstrap标识的入口函数,并启动系统服务。
提供了各服务和功能的启动入口标识。在
samgr
启动时,会调用bootstrap标识的入口函数,并启动系统服务。
-
syspara系统属性组件
系统属性组件,根据OpenHarmony产品兼容性规范提供获取设备信息的接口,如:产品名、品牌名、厂家名等,同时提供设置/读取系统属性的接口。
...
...
@@ -46,22 +45,21 @@
## 约束与限制
启动恢复子系统源代码目录和适配平台:
下表为启动恢复子系统源代码目录和适配平台。
**表1**
启动恢复子系统源代码目录和适配平台
| 名称 | 适配平台 |
| -------- | -------- |
| base/startup/appspawn_lite | 小型系统设备(参考内存
≥1M
B),如Hi3516DV300
、Hi3518EV300 |
| base/startup/bootstrap_lite | 轻量系统设备(参考内存
≥128K
B),如Hi3861V100 |
| base/startup/init_lite | 小型系统设备(参考内存
≥1M
B),如Hi3516DV300、Hi3518EV300 |
| base/startup/syspara_lite | -
轻量系统设备(参考内存
≥128KB),如Hi3861V100
<br/>
-
小型系统设备(参考内存≥1M
B),如Hi3516DV300、Hi3518EV300 |
| base/startup/appspawn_lite | 小型系统设备(参考内存
≥ 1 Mi
B),如Hi3516DV300
、Hi3518EV300 |
| base/startup/bootstrap_lite | 轻量系统设备(参考内存
≥ 128 Ki
B),如Hi3861V100 |
| base/startup/init_lite | 小型系统设备(参考内存
≥ 1 Mi
B),如Hi3516DV300、Hi3518EV300 |
| base/startup/syspara_lite | -
轻量系统设备(参考内存
≥ 128 KiB),如Hi3861V100
<br/>
-
小型系统设备(参考内存 ≥ 1 Mi
B),如Hi3516DV300、Hi3518EV300 |
-
init启动引导组件:
-
每个系统服务启动时都需要编写各自的启动脚本文件init.cfg,定义各自的服务名、可执行文件路径、权限和其他信息。
-
每个系统服务各自安装其启动脚本到/system/etc/init目录下,init进程统一扫
码
执行。
-
每个系统服务各自安装其启动脚本到/system/etc/init目录下,init进程统一扫
描
执行。
-
新芯片平台移植时,平台相关的初始化配置需要增加平台相关的初始化配置文件/vendor/etc/init/init.{hardware}.cfg;该文件完成平台相关的初始化设置,如安装ko驱动,设置平台相关的/proc节点信息。
-
配置文件init.cfg仅支持json格式。
-
新芯片平台移植时,平台相关的初始化配置需要增加平台相关的初始化配置文件/vendor/etc/init/init.{hardware}.cfg。该文件完成平台相关的初始化设置,如安装ko驱动,设置平台相关的/proc节点信息。配置文件init.cfg仅支持json格式。
-
bootstrap服务启动组件:需要在链接脚本中配置zInit代码段。
zh-cn/device-dev/subsystems/subsys-boot-syspara.md
浏览文件 @
23d5f157
...
...
@@ -3,7 +3,7 @@
## 系统参数简介
syspara系统为各系统服务提供简单易用的键值对访问接口,使得各个系统服务可以通过各自的系统参数来进行业务功能的配置。系统参数的访问和操作有
以下几个基本原语
syspara系统为各系统服务提供简单易用的键值对访问接口,使得各个系统服务可以通过各自的系统参数来进行业务功能的配置。系统参数的访问和操作有
下图所示几个基本原语:
**图1**
系统参数操作原语
...
...
@@ -13,12 +13,12 @@ syspara系统为各系统服务提供简单易用的键值对访问接口,使
| 功能 | 说明 |
| -------- | -------- |
| get | 获取系统参数的值 |
| set | 设置系统参数的值 |
| wait | 同步等待系统参数的值变更 |
| watch | 异步观察系统参数的值变更 |
| get | 获取系统参数的值
。
|
| set | 设置系统参数的值
。
|
| wait | 同步等待系统参数的值变更
。
|
| watch | 异步观察系统参数的值变更
。
|
系统参数名称采用点分格式由多段组成,每一段由字母、数字、下划线组成,总长度不超过96字节
;
系统参数名称分为两类:
系统参数名称采用点分格式由多段组成,每一段由字母、数字、下划线组成,总长度不超过96字节
。
系统参数名称分为两类:
**表2**
系统参数名称
...
...
@@ -33,7 +33,7 @@ syspara系统为各系统服务提供简单易用的键值对访问接口,使
| 类别 | 前缀 | 说明 |
| -------- | -------- | -------- |
| 常量 |
**const.**
| 常量参数,一旦赋值后续不会再变更
;
值最大长度为4096字节(包括结束符)。 |
| 常量 |
**const.**
| 常量参数,一旦赋值后续不会再变更
,
值最大长度为4096字节(包括结束符)。 |
| 可写 | 其它 | 可写参数,重启后丢失,值最大长度96字节(包括结束符)。 |
| 可持久化 |
**persist.**
| 可写并可持久化保存参数,重启后不会丢失,值最大长度96字节(包括结束符)。 |
...
...
@@ -83,12 +83,12 @@ Last line."
| -------- | -------- | -------- |
| 字符串 | const.product.name=OHOS-PRODUCT | 不支持多行字符串,不支持注释。 |
| 数字 | const.os.version.api=26 | 数字不需要引号。 |
| 布尔 | const.telephony.enable=false | 布尔型的可以为0,1
,
false,true。 |
| 布尔 | const.telephony.enable=false | 布尔型的可以为0,1
或
false,true。 |
### 系统参数DAC访问控制定义文件
当前系统参数的访问权限控制通过自主访问控制(
**Discretionary Access Control**
)方式管理,访问权限定义文件后缀名为
**".para.dac"**
,示例如下:
当前系统参数的访问权限控制通过自主访问控制(
Discretionary Access Control
)方式管理,访问权限定义文件后缀名为
**".para.dac"**
,示例如下:
```
...
...
@@ -97,7 +97,7 @@ const.product.="root:root:660"
如上所示,可以通过
**参数路径**
为相同前缀的所有系统参数定义一类访问权限信息;DAC信息通过":"分三段来描述,分别为参数的user,group以及UGO规则信息。
UGO规则信息每一位的定义如下:
UGO规则信息每一位的定义如下
图所示
:
**图2**
UGO规则信息
...
...
@@ -132,7 +132,7 @@ ohos_prebuilt_etc("ohos.para.dac") {
| 类别 | 路径 | 说明 |
| -------- | -------- | -------- |
| 内核参数 | /proc/cmdline | 内核参数中ohospara.xxx=valXXX类型的参数都转换成ohos.boot.xxx=valXXX系统参数 |
| 内核参数 | /proc/cmdline | 内核参数中ohospara.xxx=valXXX类型的参数都转换成ohos.boot.xxx=valXXX系统参数
。
|
| OS固定值 | /system/etc/param/ohos_const/
\*
.para | OS固定系统参数值参数优先加载。 |
| vendor参数值 | /vendor/etc/param/
\*
.para | 厂商参数值定义文件次优先级加载,可以覆盖system参数值定义。 |
| system参数值 | /system/etc/param/
\*
.para | 最后加载system参数值定义文件,文件中的系统参数值如果已经存在,则忽略掉。 |
...
...
@@ -140,7 +140,7 @@ ohos_prebuilt_etc("ohos.para.dac") {
## shell命令使用说明
通过shell命令中可直接操作系统参数:
通过shell命令中可直接操作系统参数
。系统参数shell命令如下表所示
:
**表6**
系统参数shell命令说明
...
...
@@ -148,7 +148,7 @@ ohos_prebuilt_etc("ohos.para.dac") {
| 功能 | 说明 |
| -------- | -------- |
| param
get
[
**key**
] | 获取指定key名称的系统参数值;如果不指定任何name,则返回所有系统参数值。 |
| param
set
**key
value
**
| 设置指定key名称的参数值为value |
| param
set
**key
value
**
| 设置指定key名称的参数值为value
。
|
| param
wait
**keyvalue**
| 同步等待指定key名称的系统参数值与value匹配。value可支持模糊匹配,如"
\*
"表示任何值,"val
\*
"表示只匹配前三个val字符。 |
| param
dump | 显示系统参数的统计信息。 |
...
...
@@ -185,8 +185,8 @@ ohos_prebuilt_etc("ohos.para.dac") {
| const
char\*
GetBuildHost(void) | 返回构建主机名。 |
| const
char\*
GetBuildTime(void) | 返回构建时间。 |
| const
char\*
GetBuildRootHash(void) | 返回当前版本hash。 |
| const
char\*
GetOsReleaseType(void) | 返回系统发布类型 |
| int
GetDevUdid(char
\*udid,
int
size) | 获取设备udid |
| const
char\*
GetOsReleaseType(void) | 返回系统发布类型
。
|
| int
GetDevUdid(char
\*udid,
int
size) | 获取设备udid
。
|
## 开发实例
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录