百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

IOS系统APP耗电量检测分析和优化

toyiye 2024-06-22 20:20 18 浏览 0 评论

耗电量不仅是衡量应用性能表现的一个重要指标,同时也是用户体验的重要组成部分。要做好?款APP,不仅仅是实现功能那么简单,我们需要考虑很多性能指标,让用户用的更爽。在开发过程中,要充分考虑到各项性能指标,比如定位精度,更高的精度,往往意味着更高的能耗,因此要平衡好精度和功耗,避免我们的APP过多的电量消耗。

耗电量基本概念


1 What Is Energy?


  • Idle状态说明 app 处于休眠状态,几乎不使用电量。
  • Active状态说明 app 处于前台工作状态,用电量?较高,我们可以看到图中的第二个Active的耗电量远高于第一个,这主要是因为 app 实际所做的工作类型不同导致的。
  • Overhead 指的是调起硬件来支持 app 功能所消耗的电量。注意:如果你的 app 就算只做了一点事, Overhead所带来的电量消耗都是一点不会减少的!
  • 图中横线以下所包区域是固定开销(Fixed Cost),横线以上区域是动态开销(Dvnamic cost)。

2 耗电大户



1)网络

网络通信时,蜂窝数据和Wi-Fi等元器件开始工作就会消耗电能。分批传输、减少传输、压缩数据、恰当地处理错误,你的app省电效果就会很显著。

2)定位

app为了记录用户的活动或者提供基于位置的服务会进行定位。定位精度越高,定位时间越长,消耗电量也就越多。所以app应该尽量降低定位精度、缩短定位时间。不需要位置信息之后立即停止定位。

3)CPU

CPU是电能消耗大户,高CPU使?量会迅速消耗掉用户的电池电量。app做的每件事几乎都需要用CPU,所以使?CPU要精打细算,真正有需要时通过分批、定时、有序地执行任务。

4)GPU

app内容每次更新到屏幕上都需要消耗电能处理像素信息。动画和视频格外耗电。不经意的或者不必要的内容更新同样会消耗电能,所以UI不可见时,应该避免更新其内容。

5)传感?和蓝?

长时间用不上加速度计、陀螺仪、磁力计等设备的动作数据时,应该停止更新数据,不然也会浪费电能。应按需获取,用完即停。蓝?活 动频度太高会消耗电能,应该尽量分批、减少数据轮询等操作。

耗电量检测方案


1 Energy Impact



1.1 Average energy Imapct

指针所指向的半圆环分为三部分,代表的是 app 的总体上的平均消耗电量评级,low(绿色区域)、high (黄色区域)、very high(红色区域)通过这张图我们可以大致了解app 电量的使用情况。理想的状态是 app 处于 low、high 状态。但是通常情况下,如果我们进行过优化,app 会处于 high、甚至very high 状态。我们需要更深入地知道究竟哪一部分的功能导致耗电量大涨 。


1.2 Average Componet Utilization

饼状图展示的是Overhead、CPU、NetWork、Location、GPU各部分耗电量的占比,通过这个占比,我们可以分析各部分耗电量是否较高。


1.3 Energy Impact

在柱状图中每根柱子代表了每秒钟的耗电情况。每根柱子都由不同颜色的矩形块堆叠而成。依次是 Overhead(红色)、CPU(蓝色)、网络(深黄)、定位(淡黄)、GPU(绿色)、后台(深灰)、前台(淡灰)、Suspend(白色) 。


1.4 总结

在使用Energy Impact的过程中,首先可以观察 Average energy Imapct 了解app的整体耗电量情况,处在什么位置,对整体有个大概的了解,然后通过 Average Componet Utilization 来观察app整体耗电量中,具体哪一部分占比较高,最后使用Energy Impact进行实时分析,分析页面各部分消耗是否是必要的,比如某个页面只在进入的时候需要获取经纬度,后面不需要实时获取经纬度,那么在进入页面获取经纬度以后,就要将定位关闭,以减少电量消耗。


优点:实时性高、数据分析可以通过图形直观展示、可以获取`Overhead(红色)、CPU(蓝色)、网络(深黄)、定位(淡黄)、GPU(绿色)、后台(深灰)、前台(淡灰)、Suspend(白色)等数据和各部分数据占比。

缺点:颗粒度较大,想做详细的分析,需要借助其它工具。比如针对CPU的消耗情况,可以通过 Time Profiler来进行分析,分析具体哪部分代码消耗较多,使用Network Profiler来分析网络的消耗情况,使用Location Profiler来分析定位的情况,详细获取各部分数据,找到电量的消耗点。


2 Energy Log


2.1 Energy Log使用



设置路径:开发者 -> Logging -> Energy -> Start Recording -> Stop Recording。

首先找到开发者,点击进入,找到Logging选项,如下图:



然后点击进入Logging选项、进入新页面,打开Energy开关,同时点击Start Recording,此时开始记录电量消耗情况,,这时你可以选择想要测试的app,在测试完毕后,点击Stop Recording,关闭电量记录功能,如下图:



最后,将手机连接到电脑,导出设备中的电量记录数据,在Energy Log中,可以看到详细的电量消耗数据,如下图:



2.2 Energy Log组成



  • Energy Usaqe Loq代表能耗消耗级别,有 0 到 20 的级别,表示应用在任何给定时间使用了多少电量,值越大表示越耗电。可以用来分析app的总体能耗。
  • CPU Activity Log 代表cpu能源消耗,包括:Foreground app Activity 、Graphics Activity、Media Activity、Other Activity。
  • Network Activity Log 代表网络能源消耗,包括:Cellular in 、Cellular out、Wi-Fi In、Wi-Fi Out。
  • Display Brightness Log代表屏幕消耗。
  • Sleep/Wake log代表仪器捕获有关设备当前状态的信息。
  • Bluetooth On/Off Loq代表蓝牙开关状态。
  • Wi-Fi On/Off Log代表Wi-Fi开关状态。
  • GPS On/Off Log代表GPS开关状态。


2.3 总结

在使用Energy Log过程中,可以通过横向比较各个维度的数据,来分析各部分的能源消耗,分析能耗的使用情况,更合理的使用?机电量。

优点:Energy Log可以测试自?app和别人app的电量消耗,有各个上面维度的详细数据,比如:某个时刻的cpu使用情况、定位使用情况,可以关联CPU、定位、总能耗消耗等数据,通过这些数据,分析使用是否合理。

缺点:Energy Log只能看整体能耗的水平,同时由于log不是实时的,要具体确定某个页面或者某个路径的能耗情况,需要??测试的时候记录一下,只能大概对照,而且不能输出精准数据。


3 Sysdiagnose


Sysdiagnose是用来诊断系统问题的工具,它包括了过去几天?,系统整体的详细功耗情况、各个App在各个硬件上的耗电情况,温度、 电流等一系列详细的数据。这些数据最终会存储在数据库中,数据库中包含多张数据表,比如在iOS12的系统中,有多达406张表。


3.1 配置

苹果在《电池诊断日志的导出指南》中详细说明了导出日志的步骤。这?简要说明一下大概的步骤。


  • 首先在你的测试机上,安装电量分析的profile,安装完成后,iOS 才会记录最详细的功耗数据,并开放读取(推荐下载后用Airdrop 发送到手机上安装);
  • 第二步,连接上 iTunes 并同步,这时 iTunes 就会自动把手机上的功耗的历史记录拷贝到电脑上;
  • 第三步,断开设备,运?你的 App,这时设备已经在记录功耗信息,记得留意你运行 App 时的时间,因为稍后要和数据库中的时间戳进行匹配;
  • 第四步,再次连接上 iTunes 并同步,这时 iTunes 就会自动把手机上的详细功耗记录拷贝到电脑上。


3.2 获取数据

到 iTunes 的同步文件夹( ~/Library/Logs/CrashReporter/MobileDevice/你的手机名/)下,找到以Powerlog_开头,后缀是.PLSQL或者.PLSQL.gz的几个文件,这些就是记录了所有功耗信息的数据库文件了,可以使用DB Browser for SQLite来打数据库。


3.3 分析数据

数据库中有多张表格,这些表格的具体用途,苹果没有详细说明,下?是一些开发者总结的部分表格信息。


表名

内容

PLBatteryAgentEventBackwardBattery

整机的电量信息,包含电流、电压、温度等信息。(每20秒记录一条数据)

PLBatteryAgentEventBackwardBattery_UI

剩余电量百分比。(每20秒记录一条数据)

PLIOReportAgentEventBackwardEnergyModel

整机不同硬件上的详细功耗数据。分别记录了 CPU、GPU、DRAM 等硬件的耗电量。

PLAccountingOperatorAggregateRootNodeEnergy

各个 App 的详细耗电数据。记录各个 App 在各个硬件上的耗电量。(每小时更新一次数据)

PLAccountingOperatorEventNoneNodes

各个硬件对应的 Node ID,以及各个 App 的对应的 Node ID。

PLAccountingOperatorEventNoneAllApps

手机中安装的所有 App 的信息

PLApplicationAgentEventForwardApplication

App运行状态记录。记录各个 App在某个时间段以什么状态运行。

PLAppTimeServiceAggregateAppRunTime

App的运行时长统计。(每小时更新一次数据。

PLBatteryAgentEventForwardLightningConnectorStatus Lighting

接口连接状态。


PLBatteryAgentEventNoneBatteryConfig

电池的配置信息。包括电池容量、循环计数、电池寿命、电池温度等信 息。

PLBatteryAgentEventNoneBatteryShutdown

电池导致的意外关机记录。

PLCameraAgentEventForwardCamera

相机使用记录。记录了相机类型和使?用相机的 App

PLConfigAgentEventNoneConfig

本机的一些配置信息和一些系统设置。

PLDisplayAgentAggregateUserTouch

屏幕点击计数。每15分钟记录一条数据。

PLDisplayAgentEventForwardDisplay

屏幕亮度信息。包括流明、尼特、亮度滑竿值等信息。

PLProcessNetworkAgentEventPointConnection

网络连接记录。记录了发起网络连接的 App、地址、端口等信息。

PLXPCAgentEventPointCacheDelete

清除缓存的记录。包括申请的空间大小、清除缓存的耗时、清除的缓存大小、服务名称、紧急程度等信息。


我们可以根据上面的表格,来分析耗电情况,比如:


  • PLBatteryAgentEventBackwardBattery_UI 可以分析剩余电量曲线
  • PLBatteryAgentEventBackwardBattery 可以分析整体耗电量和温度变化
  • PLAccountingOperatorAggregateRootNodeEnergy 和 PLAccountingOperatorEventNoneNodes 两张表,可以得到某个 Bundle ID对应的 App 在各个硬件上的耗电情况。

3.4 总结

Sysdiagnose是一个可以详细获取各个维度数据的工具,具体到某个app、某段时间、某个硬件的具体能源消耗,可以使用这个工具,进行app的不同场景的能耗数据对比、竞品app的能耗数据分析和对比,十分精确。

优点:可以精确获取各个维度的能耗消耗数据,包括:isp、apsocbase、dispaly、WiFi Data、GPU、CPU、restofsoc、GPS、DRAM等详细数据。通过这些数据,可以分析某个app的某段时间,各个维度的能耗数据,这个数据十分精确。

缺点:数据不能实时获取,部分数据需要等待一个小时才能获取,数据量较大,没有官方文档指导,需要自己分析各个表中的数据含义。

4 MetricsKit

WWDC19 Session 417, Improving Battery Life and Performance,苹果推出的三项性能监控工具分别是:

  • XCTest Metrics (开发和测试阶段)
  • MetricsKit (内测阶段和线上阶段)
  • Xcode Metrics Organizer (线上阶段)


苹果推出的性能指标监测工具可以分为两大类,分别是耗电量统计和性能监测。



4.1 Battery Metrics


耗电量的指标可以分为几种,Metrics 可以分别进行统计,可以统计的几个耗电量大户分别是:


  • Processing,包括:CPU time, GPU time, etc.这些指标可以来度量和理解 App 的复杂度,它们可以用来比对各个功能的算法效率, 发现无效的渲染等。
  • Location,包括:Cumulative usage time, bakcground time, etc.可以用来了解定位的使用情况。
  • Display 指:Average Pixel Luminance (简称 APL,平均像素亮度,即每个像素的平均亮度),在 X/XS ?手机上,OLED 屏幕显示的 UI 的颜色直接影响到能耗。
  • Networking 包括:Upload and download bytes, connectivity, etc。尽可能优化网络使用,因为它是一项高能耗的任务。
  • Accessories (蓝牙)
  • Multimedia
  • Camera

4.2 Performance Metrics


性能指标包括以下几项:


  • Hangs
  • Disk
  • Application Launch
  • Memory
  • Custom Intervals


苹果着重介绍了前四个。


1)Hang Metrics

Hang Metrics 就是我们常说的卡顿监测 ANR,它可以用来:

  • 查找哪些地方的任务可以移到后台线程
  • 利用各种 dispatches 和 queues 来减少卡顿的概率

2)Disk Metrics

这个指标记录的是磁盘逻辑写入,它用来度量磁盘使?情况,可以用来:

  • 定位多余的磁盘写入检
  • 查合并策略

3)Application Launch Metrics

可以?来度量 App 启动或恢复所消耗的时间。

  • 了解启动时的耗时因素,例如数据库加载对启动耗时的影响有多大
  • 查看启动和恢复这两种路径下的不同耗时

4)Memory Metrics

内存的管理很重要,它也可以影响到应用的启动速度,以及在后台时,被终止的可能性。Memory Metrics 用于查看平均内存占用,以及峰值内存占?。它可以用来检测内存的使用情况,例如:

  • 定位难以复现的内存泄漏
  • 减少应?挂起后的平均内存占用(有助于推迟应用被终止的时间)

优化建议


1 网络

只要app执?网络操作,就会产?大量的能耗,网络硬件为了响应下一次任务,往往会持续活跃一段时间,下面是多次网络的能耗图。


1.1 缩减网络请求

1)减少、压缩网络数据。可以降低上传或下载的多媒体内容质量和尺寸等。

2)使用缓存,不要重复下载相同的数据。

3)使?断点续传,否则网络不稳定时可能多次传输相同的内容。

4)网络不可用时不要尝试执行网络请求,尽量只在Wi-Fi情况下联网。

5)让用户可以取消长时间运行或者速度很慢的网络操作,设置合适的超时时间。

6)网络请求失败后用SCNetworkReachability的通知监测网络状态,网络可用后再重试。


1.2 延迟联网

1)分批传输。比如,下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块地下载。如果提供广告,一次性多下载一些,然后再慢慢展示。如果要从服务器下载电子邮件,一次下载多条,不要一条一条地下载。

2)网络操作能推迟就推迟。如果通过HTTP上传、下载数据,建议使用NSURLSession中的后台会话,这样系统可以针对整个设备所有的网络操作优化功耗。将可以推迟的操作尽量推迟到设备充电状态并且连接Wi-Fi时进行,比如同步和备份工作。


2 定位

1)如果你的app只是需要快速确定一下用户的位置,最好?CLLocationManager的requestLocation (iOS9引?入)方法。定位完成之后会自动让硬件断电。

2)除非是在导航的时候,app大部分时间不需要实时更新,降低位置的更新频率。

3)尽量降低定位精度。iOS设备默认采用最?精度定位,如果你的app不是确实需要米级的位置信息,不要用最高精度(kCLLocationAccuracyBest)或10米左右的精度(kCLLocationAccuracyNearestTenMeters)。一般来说Core Location提供的精度比你设置的要好,比如你设置为3公里左右的精度,可能会收到100米左右的精度信息。

4)如果定位精度一直达不到设置的精度时,停止更新位置,稍后再试。

5)需要后台更新位置时,尽量把pausesLocationUpdatesAutomatically设为YES,如果用户不太可能移动的时候系统会自动暂停位置更 新。

6)后台定位时延时更新位置。如果要做一个健身类的软件追踪用户徒步的距离,可以等用户移动一段距离或者过一段时间之后再更新位置,这样可以让系统优化能耗。

3 CPU

3.1 尽量减少计时器使用

使用计时器时,设置一个合适的超时,不再需要时及时关闭重复性定时器。用事件通知代替定时器。有些app用定时器监控文件内容、网络或者其他状态的变化,这会导致CPU无法进入闲置状态而增加功耗。


3.2 减少后台工作

实现UIApplicationDelegate中的方法,应用进入后台前做好暂停任务,保存数据等工作。如果确实需要完成用户执行的一些任务,应该调用UIApplicationDelegate中的beginBackgroundTaskWithExpirationHandler: 方法,这样后台任务可以继续执行几分钟。任务执行完毕后一定要调用endBackgroundTask:方法,不要等着系统强行挂起进程。


3.3 用QoS分级有序工作

多个app和众多操作需要共享CPU、缓存、网络等资源,为了保持高效,系统需要根据不同任务的优先级智能地管理这些工作。比如更新UI这种重要的事需要多分配资源,而一些后台任务可以延迟一些执行。服务质量(quality of service, 以下简称QoS, iOS8引?入)级别可以通过NSOperation, NSOperationQueue, NSThread objects, dispatch queues, 和pthreads (POSIX threads)指定工作的优先级。


3.4 优化I/O访问

app每次执行I/O任务,比如写?件,会导致系统退出闲置模式。而且写入缓存格外耗电。通过下列方法可以提高能效、改善app性能。

1)减小写入数据。数据有变化再写文件,尽量把多个更改攒到一起一次性写入。如果只有几个字节的数据改变,不要把整个文件重新写入一次。如果你的app经常要修改大?件?很少的内容,可以考虑用数据库存储这些数据。

2)避免访问存储频度太高。如果app要存储状态信息,要等到状态信息有变化时再写入。尽量分批修改,不要频繁地写入这些小变动。

3)尽量顺序读写数据。在文件中跳转位置会消耗一些时间。

4)尽量从?件读写大数据块,一次读取太多数据可能会引发一些问题。比如,读取一个32M?件的全部内容可能会在读取完成前触发内容分页。

5)读写大量重要数据时,考虑用dispatchio,其提供了基于GCD的异步操作文件I/O的API。用dispatchio系统会优化磁盘访问。

6)如果你的数据由随机访问的结构化内容组成,建议将其存储在数据库中,可以使用SQLite或CoreData访问。特别是需要操作的内容可能增长到超过几兆的时候。

7)了解系统如何缓存文件、如何优化缓存的使用。如果你不打算多次引用某些数据,不要?己缓存数据。

4 GPU

1)减少app使用的视图数量。

2)少用运算获得圆角,不论view.maskToBounds还是layer.clipToBounds都会有很大的资源开销。

3)尽量少用透明或半透明,会产?额外的运算。

4)执行动画时不要修改帧率。比如,你的app帧率是60fps,整个动画就保持这个帧率不要变。

5)视频播放时,app尽量不要在全屏视频上添加额外的图层(即使是隐藏的图层)。

5 优化通知

1)尽量用本地通知(local notification),如果你的app不依赖外部数据,而是需要基于时间的通知,应该用本地通知,可以让设备的网络硬件休息一下。

2)远程推送有两个级别,一个是立即推送,另一个是针对功耗优化过的延时推送。如果不是真的需要即时推送,尽量使?延时推送。

总结

耗电量分析是应用开发中很难的课题,也是衡量性能的重要指标,做好电量优化,可以大幅度提升用户体验,在实际开发过程中,电量消耗往往是一个综合的结果,?到日常的代码习惯,积少成多,大到网络的乱用、不合理的网络超时、不合理的定位使用、不合理的CPU使用,都会带来能耗的过多消耗,而这些问题不仅仅会影响电量,还会影响用户体验。我们需要提高日常开发的代码质量,了解不同实现方式的差异点,优化页面卡顿,优化网络使用,优化GPS使用等等,只有综合这些因素,才能获得较好的用户体验。

在做耗电量分析的时候,?先要清楚耗电量较大的点,比如:网络、定位、CPU、GPU,从这些点入手分析,再详细分析每个点,细分每个点中的一些细节的影响,比如:网络中可能会存在导致耗电量过高的因素,我们可以使用哪些优化方法,同时根据我们的需求特点,怎么来优化,最终找到可优化点的,找到解决方案。在优化点寻找的过程中,我们?先可以使用Energy Impact来实时分析,各个维度指标是否有问题,占比是否合理,然后再通过Time Profiler、NetWork Profiler、Location Profiler等工具对各项指标进行详细分析,寻找优化点。其次我们可以使用Energy Log来横向对比各个维度的数据,来分析各个维度对总功耗的影响,比如:wifi数据传输和4G数据传输时,耗电量的对比,打开蓝牙和未打开蓝牙,能耗数据的对比,查看各个维度对能耗消耗影响的权重。然后我们可以使用Sysdiagnose可以进行不同场景、竞品app的对比分析,查找app的可优化点,也可以进行各种能耗数据的对比分析,以及优化前后的能耗数据对比,获取最终的优化效果。Sysdiagnose中的数量比较精确,同时数据比较全面,可以挖掘更多的信息,来辅助我们进行电量优化。


附:iPhone各代电池容量


相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码