Android 性能稳定性测试工具 mobileperf 开源 (天猫精灵 Android 性能测试-线下篇)
<h1 class="article-title" data-spm-anchor-id="a2c6h.12873639.article-detail.i11.319b617choYMct">Android 性能稳定性测试工具 mobileperf 开源 (天猫精灵 Android 性能测试-线下篇)</h1><p>这篇文章写得很好!感谢阿里云开发者社区!!!</p>
<p>原文地址:</p>
<p><span style="background-color: rgba(255, 255, 0, 1)">https://developer.aliyun.com/article/761286</span></p>
<p> </p>
<h1 id="slide-0" data-spm-anchor-id="a2c6h.12873639.article-detail.i13.319b617choYMct">背景</h1>
<p>天猫精灵业务主要有如下挑战:</p>
<p>1、除了天猫精灵手机 APP,还有带屏天猫精灵上很多 APP 都需要支持,比如天猫精灵 CC 上有 13 个 app,每个 app 使用场景各有不同,涵盖了通讯录、视频、音乐、购物等各种场景<br>2、相比手机 app,除了点击操作的触屏链路,天猫精灵还有语音链路</p>
<p>3、手机 app monkey test 一般可能也就云测平台上跑几个小时,语音压测需要连续测试 72 个小时以上,测试时长远超云测工具,对工具的稳定性提出了新的要求<br>4、相对现在定价动辄几千块,均价 2 千左右的手机,天猫精灵定价只有几百,硬件配置差些,所遇到的性能 稳定性挑战会更严峻</p>
<h1 id="slide-1">需求</h1>
<p>本着前期先能发现问题,再深入定位问题,所以确定了线下、线上分步走的策略</p>
<p>1、线下方案,能方便采集性能数据,工具要支持 Android 手机、天猫精灵各种 Android 定制设备,支持 Android 全版本,轻量化,使用低门槛,尽可能少侵入甚至零侵入设备<br>2、线上性能指标 问题定位</p>
<p>本文是 Android 线下篇</p>
<h1 id="slide-2">线下方案选型</h1>
<h3>工具选型</h3>
<p>Android App</p>
<p>代表:开源工具腾讯 GT、网易 Emmagee<br>劣势:Android 低版本有些功能需要 <span style="background-color: rgba(255, 255, 0, 1)">root</span>,Android 高版本跨进程获取数据,<span style="background-color: rgba(255, 255, 0, 1)">权限限制</span>,不兼容</p>
<p>PC adb 工具</p>
<p><span style="background-color: rgba(255, 255, 0, 1)">优势:非侵入,权限高,能发现问题</span><br><span style="background-color: rgba(0, 255, 255, 1)">劣势:需要连接数据线,便携性差点</span><br>**<br>SDK**</p>
<p>劣势:侵入式,需集成 SDK,不利于做竞品测试</p>
<p><span style="background-color: rgba(255, 255, 0, 1)">GT github 上已表示 Android GT 后续不再支持 GT APP 版本,只支持 GT SDK</span></p>
<p>由于 <span style="background-color: rgba(255, 255, 0, 1)">Android 权限控制越来越严格,通过 APP 跨进程获取性能数据在 Android 高版本已越来越困难,由于 <span style="background-color: rgba(0, 255, 255, 1)">adb shell 权限比较高</span>,相信 Android 会一直开放开发者权限</span>,故方案选型阶段,采用了依赖 adb 的方案,开发了一套 Android 性能数据采集工具 mobileperf</p>
<p>还有一种思路,仍然是 app 形态,但用了 adb wifi 通道,look 之前也有过一些测试工具 app 的经验,相比采用 adb usb 方式 mobileperf 的担忧:</p>
<p>1、测试工具 app,应用进程优先级,还是会受 Android 限制,<span style="background-color: rgba(255, 255, 0, 1)">担心系统资源不足,测试进程优先级不高,被系统 kill 概率大</span>,在 IOT 低端设备上被 kill 概率更大,进程保活是业界难题,黑科技手段层出不穷,并且存在随时被官方封杀的风险,路只会越走越窄,mobileperf 是 PC 程序,除非 adb usb 方式不能用了,设备失联,关机等恶劣情况,都 OK,与其花费很大精力探索各种黑科技上,还不如把精力放在 Android 允许范围内倒腾。</p>
<p>2、带屏天猫精灵都是<span style="background-color: rgba(255, 255, 0, 1)">定制 Android 系统,测试工具 app 可能要做单独的适配,兼容性成本高点</span>,这点 mobileperf 不用担心,只要是 Android 系统、adb 能用就可以,在各种 Android 定制设备,使用成本更低。</p>
<p>3、<span style="background-color: rgba(255, 255, 0, 1)">由于是 APP,系统需要单独分配资源</span>,比如工具发现的 anr,开发童鞋一看 cpu 占用信息,如果发现测试工具 app 占用 cpu 较高,就很容易受到挑战,找工具的锅(不排除有些 ANR 确实是工具导致的),而 mobileperf 采集都依赖系统命令,这种影响小些。</p>
<p>4、长时间测试,比如 72 小时以上,adb wifi 担心会有点不稳定,毕竟要依赖网络。</p>
<p> </p>
<h3>工具对比</h3>
<p>mobileperf 跟 GT APP 对比如下:</p>
<p><img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810113348439-49479285.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h3>架构</h3>
<p>mobileperf 整体架构图:</p>
<p><img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810113427051-1845836261.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h3>工具自身影响</h3>
<p>mobileperf 对 PC 的影响</p>
<p><img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810113458742-511031791.png" alt="" loading="lazy"></p>
<p> </p>
<p>测试 PC:MacBook Pro (Retina,15-inch, Mid 2015) 2.2 GHz 四核 Intel Core i7</p>
<p>工具稳定性:mobileperf 能支持跑 72 个小时以上,<span style="background-color: rgba(0, 255, 255, 1)">adb 断开重连都能继续采集</span></p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i2.319b617choYMct">工具适用性:支持 mac linux windows 平台</p>
<p> </p>
<h3>工具 Android 兼容性验证</h3>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct">mobileperf Android 版本兼容性验证结果如下</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"><img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810113724259-73791327.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h1 id="slide-3" data-spm-anchor-id="a2c6h.12873639.article-detail.i18.319b617choYMct">效果</h1>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i3.319b617choYMct">mobileperf 在项目中使用 1 年半,天猫精灵总共发现了性能 稳定性类问题几百个,bug 解决率都是 100%</p>
<h1 id="slide-4">采集原理</h1>
<h3>cpu</h3>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i7.319b617choYMct">方案调研<br>1、dumpsys cpuinfo<br>2、top 命令</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i8.319b617choYMct">3、通过 proc/stat 计算 cpu 使用率</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i9.319b617choYMct">两者区别:Android CPU 使用率:top 和 dump cpuinfo 的不同,看网上一番讨论,<span style="background-color: rgba(255, 255, 0, 1)">top 更准</span></p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i10.319b617choYMct">通过实验发现采集<span style="background-color: rgba(255, 255, 0, 1)">频率非常快</span>时,<span style="background-color: rgba(255, 255, 0, 1)">top 有点耗 cpu</span>,对手机本身性能有影响,自测,采集频率 1s,top 在低端手机上(红米)会占到 7%(100%统计方式)的 cpu 使用率,天猫精灵采集频率 5s,会有 20%占用(400%统计方式),发现 top 的底层实现是读取 proc 文件,top 对每个进程都有计算</p>
<p>网上提供了一种计算方式,原理上跟 top 一样,<span style="background-color: rgba(0, 255, 255, 1)">如果计算指定进程的 cpu 使用率,只需读对应的 proc 文件,通过 jiffies 计算就可以了,这样比 top 方式占用 cpu 低</span>,计算方式如下</p>
<p>整机 cpu 使用率</p>
<p>通过读取/proc/stat ,这个文件包含了所有 cpu 核的汇总情况,所以后面计算不用考虑核数,占用率不会超过 100%</p>
<p>cpu 使用时间 = user+nice+system+iowait+irq+softirq</p>
<p>CPU 总时间=user+nice+system+idle+iowait+irq+softirq = cpu 使用时间 +cpu idle 时间</p>
<p>总 cpu 使用率=(cpu 使用时间 2-cpu 使用时间 1)/(cpu 总时间 2-cpu 总时间 1)*100%</p>
<p>进程 cpu 使用率</p>
<p>通过读取/proc/pid/stat</p>
<p>进程 cpu 使用时间 = utime+stime</p>
<p>进程 cpu 使用率=(进程 cpu 使用时间 2-进程 cpu 使用时间 1)/(cpu 总时间 2-cpu 总时间 1)*100%</p>
<p>选定方案<br>采集时间间隔 ,配置文件中默认<span style="background-color: rgba(255, 255, 0, 1)"> 5 秒,由于对采集频率要求不高,top 支持同时采集多进程</span>,结果简单易处理,实时性 可信度高,决定采用 top 的方式</p>
<p>测试过程中会生成 cpuinfo.csv,可以测试过程中查看,表中各列解释</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810141811435-1408176094.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> 汇总 xlsx 文件会在测试结束后生成,xlsx 数据跟 csv 数据完全一致,xlsx 汇总是根据 csv 的数据画的曲线(csv 没有画图功能)</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810141854299-608000445.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h3> 内存</h3>
<p>整机内存 可用内存通过 dumpsys meminfo 获取 Total RAM 、Free RAM</p>
<p>各进程 pss 通过 dumpsys meminfo package 获取 TOTAL 行 Pss Total 所在列的值,各进程<span style="background-color: rgba(0, 255, 255, 1)"> PSS 也可以通过 dumpsys meminfo 获取,只是拿不到各进程更详细的内存占比情况</span>,比如堆大小、native、system、so 大小等</p>
<p>经在 CC 上测试发现 <span style="background-color: rgba(255, 255, 0, 1)">dumpsys meminfo 比 dumpsy meminfo package 耗时长</span>,<span style="background-color: rgba(0, 255, 255, 1)">dumpsys meminfo 耗时 6s 多,dumpsys meminfo package 能在一秒内完成</span>,采集频率 5s,<span style="background-color: rgba(0, 255, 255, 1)">dumpsy meminfo 会导致 CC 上 system_server 系统进程 cpu 由 2%<strong>增高到 80%</strong></span>,所以降低了 dumpsys meminfo 采集频率,采用 10 倍设置频率采集(比如 dumpsys meminfo package 5s,dumpsy meminfo 则 50s)</p>
<p>由于要支持多进程的情况,现在各进程 pss 通过解析 dumpsys meminfo 结果得到,<span style="background-color: rgba(0, 255, 255, 1)">dumpsys meminfo package 来获取各个进程的<span style="background-color: rgba(255, 255, 0, 1)">详细</span>内存情况</span></p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i22.319b617choYMct">在测试过程中会生成一个 meminfo.csv 文件,可以查看,表中各列解释</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810143843470-885558981.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> mem table<br>这个 csv 表格是用 dumpsys meminfo 得出的,汇总 xlsx 文件会在测试结束后生成,对应 meminfo 这个表格</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810144023131-439930156.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> 每个进程会有 pss_部分包名的 csv 表格,这个表格是用 dumpsys meminfo package 得出的</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810144149438-107521999.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> 能把每个进程的详细内存展示出来</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i27.319b617choYMct">汇总 xlsx 中对应 pss_部分包名这个表格</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810144300819-1519441840.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> 如果进程发生了内存泄露,根据曲线,很方便一眼就看出是哪部分导致泄漏</p>
<p>为了帮助定位内存泄漏问题,工具每隔一个小时会执行 am dumpheap package ,dump 进程内存,但不能像 LeakCanary 直接翻译出 GC 引用链,仍需人工分析下</p>
<h3 data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> 流畅度(fps/丢帧)</h3>
<p>fps 通过 <span style="background-color: rgba(255, 255, 0, 1)">dumpsys SurfaceFlinger</span> 或 <span style="background-color: rgba(255, 255, 0, 1)">dumpsys gfxinfo</span>(android8.0 之后)获得最近 128 帧数据计算得出,fps=帧数/耗费时间</p>
<p>如果以上两种方式都不 OK,机器有 root,用 service call SurfaceFlinger 1013 获取帧数</p>
<p>通过 dumpsys SurfaceFlinger 的方式还会计算丢帧 janky 值</p>
<p>丢帧:相邻两次绘制之间的丢帧数,丢帧数越多,说明问题越严重,<span style="background-color: rgba(255, 255, 0, 1)">mobileperf 默认丢帧数超过 10 帧算是严重丢帧</span></p>
<p>流畅度数据在 fps.csv 中</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i30.319b617choYMct">表中各列解释</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810144530277-703488825.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h3> 页面打开耗时</h3>
<p><span style="background-color: rgba(255, 255, 0, 1)">mobileperf 从 logcat 日志中抓取 am_activity_fully_drawn_time</span> 和 <span style="background-color: rgba(255, 255, 0, 1)">am_activity_launch_time</span>(大多数情况)日志,</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i32.319b617choYMct">会生成 launch_logcat.csv</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810144634835-919965646.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> </p>
<p>不过这种方式有个弊端,日志的耗时不能完全反馈真实的体验耗时,我们内部已有其他方案测试启动耗时</p>
<h3>monkey(可限制 activity)</h3>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i34.319b617choYMct">mobileperf 调用了 Android 原生的 monkey,如果您想限制在指定内 activity 内跑 monkey ,可以通过配置项,开启 monkey 后,会在测试目录下生成 monkey.log</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810144854831-150608061.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h3> logcat 日志(支持异常日志检测)</h3>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i36.319b617choYMct">工具会保留全量 logcat 日志,每隔 60 万行会新建文件,辅助定位问题</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810145044421-1519362104.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> 如果配置文件中配置了异常日志</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810145238177-605003949.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> 会将 logcat 中出现的异常日志都保存在 exception.log 中</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810145357657-1047629584.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> 根据异常汇总日志,再去 logcat 日志查看详细上下文信息,可以快速定位问题</p>
<h3>流量</h3>
<p>通过读取<span style="background-color: rgba(255, 255, 0, 1)">/proc/net/xt_qtaguid/stats</span> 文件获取,因为 Android 提供的流量统计 API – <span style="background-color: rgba(255, 255, 0, 1)">TrafficStats</span> 中,对 uid 进行流量统计的方法,能区分应用,底层就是读取了该文件,参考Android 性能测试之网络流量</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i7.319b617c8uqTsf">流量数据在 traffics_uid.csv 中,表中各列解释</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810145646267-1165412221.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<h3> 电量</h3>
<p>先通过 dumpsys batteryproperties 获取,如果获取不到,再通过 <span style="background-color: rgba(255, 255, 0, 1)">dumpsys battery</span> 获取(Android9)</p>
<p>问题:插着 usb,这两种方式获取到的并不精准,并非专业级电流电量测试,只能作为参考</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i9.319b617c8uqTsf">电量数据在 powerinfo.csv 中,表中各列解释</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> <img src="https://img2022.cnblogs.com/blog/1034798/202208/1034798-20220810145816933-1525747862.png" alt="" loading="lazy"></p>
<p> </p>
<p> </p>
<p> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i11.319b617c8uqTsf">由于功耗软件测试方式不太精准,我们内部已用硬件方案测试功耗,此项 mobileperf 中默认关闭</p>
<h3 data-spm-anchor-id="a2c6h.12873639.article-detail.i11.319b617c8uqTsf">常驻进程 pid 监控</h3>
<p>天猫精灵是整机,跟很多手机 app 不一样,是应用级别 app,可能会被用户手动 kill 掉,天猫精灵上有些系统优先级进程,不能挂掉,一旦挂掉,会导致无法使用,<span style="background-color: rgba(255, 255, 0, 1)">所以 mobileperf 新增了常驻进程 pid 监控,一旦 pid 发生了变化,认为发生了异常</span></p>
<pre><code class="hljs ini"><span class="hljs-attr">pid_change_focus_package=com.alibaba.ailabs.genie.smartapp<span class="hljs-comment">;com.alibaba.ailabs.genie.smartapp:core<br><br><br></span></span></code></pre>
<h3>磁盘剩余空间检查</h3>
<p>天猫精灵跟很多手机 app 不一样,随便压测就是 3 天以上,如果有写文件不正常,占满磁盘空间,会导致机器彻底无法使用,影响用户体验,所以测试结束时,添加了对磁盘剩余空间检查,如果使用空间超过 80%,则自动提单</p>
<h3>进程线程数</h3>
<p>通过进程名获取 pid,ls -lt /proc/pid/task,统计多少行数即线程数</p>
<p>奉上 mobileperf 的 github 地址:https://github.com/alibaba/mobileperf 如果您觉得有帮助,请给个 star!同时如果有疑问的话,可以加入该钉钉答疑群。</p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p>这篇文章写得很好!感谢阿里云开发者社区!!!</p>
<p>原文地址:</p>
<p><span style="background-color: rgba(255, 255, 0, 1)">https://developer.aliyun.com/article/761286</span></p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p data-spm-anchor-id="a2c6h.12873639.article-detail.i17.319b617choYMct"> </p>
<p> </p><br><br>
来源:https://www.cnblogs.com/111testing/p/16571777.html
頁:
[1]