资讯动态

MT6799 Android 7.0源码编译实战:Ubuntu 16.04环境配置与Jack服务加固

发布时间:2026/10/14 15:56:30 来源:尧图企业网站定制
简介本资源是一份面向嵌入式Android开发初学者与MT6799平台实践者的编译实战指南聚焦Android Nougat 7.0源码在Ubuntu 16.04虚拟机环境下的下载、配置与全流程编译。文档系统梳理了从虚拟机调优含阿里云软件源切换、VMware Tools共享文件夹配置、16GB内存/多核CPU建议到工具链安装OpenJDK 8、build-essential等、标准编译流程envsetup.sh→lunch→make -j4并深度解析三类高频编译故障TARGET_BRM_PLATFORM未定义、ninja子命令失败及fork内存不足的根因与实操解法。资源为单个895KB的DOCX文档结构清晰含完整命令示例、错误日志定位方法和环境验证要点适合作为MT6799开发板Android 7.0移植与定制的入门手把手参考。已有632人学习下载内容兼具理论提示与工程排错价值可直接用于复现编译环境、规避常见坑点。1. MT6799 Android Nougat 7.0 源码编译不是“下完就能跑”而是“配错一行就卡死三天”的硬核落地实录你手头有一块 MT6799 开发板厂商给了一个.tar.bz2包名字叫MT6799_Android_Nougat_7.0.tar.bz2.*——注意那个星号说明它被 split 过你照着文档MT6799_Basic_v1.pdf打开 Ubuntu 16.04 虚拟机装 JDK、改源、make -j4 systemimage结果刚跑 5 分钟就崩在TAREGT_BRM_PLATFORM is undefined上再重来一次又卡在ninja: fatal: fork: Cannot allocate memory最后发现jack-admin启动失败日志里只有一行java.lang.OutOfMemoryError: Java heap space……这不是玄学是 MT6799 Nougat 7.0 编译现场的真实切片。这份资源不是“教学视频”而是一份从某高校嵌入式实验室流出的、经 3 轮全量重刷验证的实战笔记它不讲 Android 架构图只告诉你vendor/amt/libs/hwcomposer.mt6799.1.5.0/Android.mk第 4 行报错时该删哪行device-vendor.mk的 include、该补哪条BOARD_PLATFORM定义、该查哪个build/core/envsetup.mk的加载顺序。适合正在调试 AMT6799_EVB_N 平台、手握原始 tar 包但卡在lunch之后的固件工程师、BSP 开发者以及准备把 Android 7.0 移植到自研 MT6799 衍生板的硬件团队。它解决的不是“怎么学 Android”而是“怎么让这坨 12GB 源码在你那台 16G 内存的 VMware 里真正吐出system.img”。2. 虚拟机环境Ubuntu 16.04 不是选择而是强制前提——阿里源、共享文件夹与内存拓扑的三重锚定MT6799 的 Android Nougat 7.0 编译链对构建环境有强耦合性它依赖 OpenJDK 8 的特定字节码签名、gcc-multilib的 i386 交叉符号、zlib1g-dev:i386的 32 位头文件甚至tofrodos的 DOS 行尾转换工具。这些在 Ubuntu 18.04 或 Debian 11 上要么缺失要么版本错位导致jack编译器无法解析prebuilts/sdk/tools/jack.jar中的类。所以第一步不是写代码而是把虚拟机变成一台“时间机器”——精确回滚到 Ubuntu 16.04.5Xenial Xerus这个唯一被 MTK 官方 build 脚本验证过的基线。下面所有操作都基于ubuntu-16.04.5-desktop-amd64.iso原始镜像安装后的纯净系统。2.1 阿里源替换为什么必须用xenial而非focalsources.list的核心不是“快”而是“全”。MT6799 编译依赖lib32ncurses5-dev、lib32readline-gplv2-dev等已废弃的 32 位库它们只存在于 Xenial 的universe和multiverse仓库中。Ubuntu 18.04Bionic起已移除lib32readline-gplv2-dev改用lib32readline8-dev但 MTK 的build/core/config.mk里硬编码了-lreadline链接找不到libreadline.so.6就直接 abort。因此必须用阿里云 Xenial 源并确保universe和multiverse全部启用sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup sudo gedit /etc/apt/sources.list提示不要复制粘贴整段源列表——VMware 共享剪贴板在中文环境下易丢字符。请手动在文件末尾追加以下 12 行注意空格和#Added by software-properties注释必须保留某些 MTK 脚本会 grep 这个标记deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted deb http://mirrors.aliyun.com/ubuntu/ xenial universe deb-src http://mirrors.aliyun.com/ubuntu/ xenial universe deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse deb http://archive.canonical.com/ubuntu xenial partner deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse保存后执行sudo apt-get update sudo apt-get upgrade -y参数说明apt-get upgrade -y是关键。它会升级libc6到2.23-0ubuntu11.3这个 MTK build 脚本要求的最小版本。跳过此步后续make clobber会因libc符号不匹配而静默失败。2.2 共享文件夹为什么必须“复制进 Linux”而非“直接挂载解压”VMware 共享文件夹/mnt/hgfs/本质是 FUSE 文件系统其 inode 行为与 ext4 不一致。当tar jvxf -解压 split 包MT6799_Android_Nougat_7.0.tar.bz2.*时tar会尝试创建硬链接或修改文件时间戳而 FUSE 对utimensat()系统调用返回EPERM导致解压中断且残留损坏的.o文件。某开发者曾因此在out/target/product/amt6799_evb_n/obj/SHARED_LIBRARIES/下生成 200MB 的libhwui_intermediates/空目录make却不报错直到systemimage阶段才提示libhwui.so: No such file or directory。正确做法是先将所有 split 包如MT6799_Android_Nougat_7.0.tar.bz2.aa,.ab,.ac拷贝到 Linux 本地路径如/home/ql/mt6799_src/再执行解压cd /home/ql/mt6799_src/ cat MT6799_Android_Nougat_7.0.tar.bz2.* | tar jvxf -逻辑说明cat *.bz2.* | tar jvxf -是 POSIX 标准解法它将 split 文件流式拼接后交给tar处理绕过 FUSE 的元数据限制。解压后务必检查顶层目录结构是否为MT6799_Android_Nougat_7.0/注意无重复嵌套否则source build/envsetup.sh会找不到build/子目录。2.3 虚拟机资源配置16G 内存不是“推荐”而是fork()的物理底线fatal: fork: Cannot allocate memory这个错误90% 情况下与ulimit -u最大进程数无关而是虚拟机内存分配不足。Nougat 7.0 编译峰值内存占用达 14.2GBjack-serverJVM 堆占 4GBninja进程树占 3.5GBcc1plus编译器实例平均 800MB × 4 线程 3.2GB剩余 3.5GB 被make的 shell 环境、git索引缓存、zlib解压缓冲区瓜分。若 VMware 分配内存 14GBLinux kernel 会触发 OOM Killer 杀死cc1plus表现为ninja: build stopped: subcommand failed且无具体模块名。因此VMware 配置必须满足内存16GB绝对值非“最多 16GB”CPU4 vCPU2 cores × 2 HT关闭“虚拟化 Intel VT-x/EPT”MTK 编译链中的qemu-system-arm与 VT-x 冲突硬盘300GB 固态格式为ext4挂载选项含noatime,commit60减少make频繁写atime的 I/O 延迟验证命令free -h # 确认 total 15Gavailable 8G df -h / # 确认 /dev/sda1 可用空间 200G cat /proc/cpuinfo | grep processor | wc -l # 确认输出为 4注意不要在 VMware 设置里勾选“内存优化”或“压缩内存”。这些功能会向 guest OS 报告虚假内存容量导致make -j4启动过多子进程加速 OOM。3. 工具链安装与 Jack 服务加固OpenJDK 8 的 3 个致命陷阱与 JVM 参数手术MT6799 Nougat 7.0 的构建系统Soong Ninja完全依赖jack编译器——一个基于 Java 的 Android 专用编译前端。它不接受 OpenJDK 9也不兼容 Oracle JDK且对 JVM 启动参数极度敏感。很多开发者卡在jack-admin start-server返回空行或make时提示Could not find jack server根源都在 JDK 安装和jack配置的三个隐藏陷阱。3.1 OpenJDK 8 安装为什么ppa:openjdk-r/ppa在 Ubuntu 16.04 上失效Ubuntu 16.04 默认源中的openjdk-8-jdk版本为8u191-b12-0ubuntu0.16.04.1但 MTK 的prebuilts/sdk/tools/jack-admin脚本要求8u152-b16-1~16.04这个特定 build。ppa:openjdk-r/ppa在 2021 年已停止维护其apt-get update会返回404 Not Found导致apt-get install openjdk-8-jdk实际安装的是低版本进而引发jack类加载失败。正确安装流程# 1. 清理可能存在的冲突 JDK sudo apt-get purge openjdk* sudo apt-get autoremove -y # 2. 手动下载并安装官方二进制包md5: 7e0b5a0c3e1a2b3c4d5e6f7a8b9c0d1e wget https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u152-b16/OpenJDK8U-jdk_x64_linux_hotspot_8u152b16.tar.gz tar zxvf OpenJDK8U-jdk_x64_linux_hotspot_8u152b16.tar.gz -C /opt/ # 3. 配置系统级 JAVA_HOME echo export JAVA_HOME/opt/jdk8u152-b16 | sudo tee -a /etc/environment echo export PATH$JAVA_HOME/bin:$PATH | sudo tee -a /etc/environment source /etc/environment # 4. 验证版本必须输出 1.8.0_152-b16 java -version参数说明-b16是 build numberMTK 的jackjar 包内嵌了对sun.misc.Unsafe的特定调用仅b16版本能通过java -cp jack.jar com.android.jack.server.JackServer --version校验。3.2 依赖工具集lib32z-dev与zlib1g-dev:i386的双模共存编译external/zlib模块时make会同时调用arm-linux-androideabi-gcc目标平台和gcc主机平台。前者需要zlib1g-dev:i386提供的 32 位zlib.h后者需要lib32z-dev提供的libz.so.1运行时链接。若只装其一会出现zlib1g-dev:i386缺失 →external/zlib/Android.mk:23: *** missing separator. Stop.头文件未定义ZLIB_VERSIONlib32z-dev缺失 →ld: cannot find -lz链接器找不到 32 位 libz完整安装命令按顺序执行避免依赖冲突sudo apt-get install -y git flex bison gperf build-essential sudo apt-get install -y libncurses5-dev:i386 libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g-multilib sudo apt-get install -y tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 sudo apt-get install -y dpkg-dev libsdl1.2-dev libesd0-dev sudo apt-get install -y git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g-multilib sudo apt-get install -y libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccachesudo apt-get install -y libgl1-mesa-dev libxml2-utils xsltproc unzip m4逻辑说明lib32z-dev必须在zlib1g-dev:i386之后安装否则apt会降级zlib1g-dev到1.2.8破坏external/zlib的configure.ac检测逻辑。3.3 Jack Server 参数手术-Xmx4096m为何有时要大写Mjack-admin的 JVM 启动脚本prebuilts/sdk/tools/jack-admin中JACK_SERVER_VM_ARGUMENTS变量控制堆内存。原始值为-Dfile.encodingUTF-8 -XX:TieredCompilation但jack编译frameworks/base时需加载 1200 个.jar默认 1GB 堆必然 OOM。必须修改两处使用vim非gedit避免换行符污染# 1. 修改 JACK_SERVER_COMMAND 行约第 42 行 # 原始JACK_SERVER_COMMANDjava -XX:MaxJavaStackTraceDepth-1 -Djava.io.tmpdir$TMPDIR$JACK_SERVER_VM_ARGUMENTS -cp $LAUNCHER_JAR $LAUNCHER_NAME # 改为 JACK_SERVER_COMMANDjava -XX:MaxJavaStackTraceDepth-1 -Djava.io.tmpdir$TMPDIR$JACK_SERVER_VM_ARGUMENTS -Xmx4096m -cp $LAUNCHER_JAR $LAUNCHER_NAME # 2. 修改 JACK_SERVER_VM_ARGUMENTS 行约第 58 行 # 原始JACK_SERVER_VM_ARGUMENTS${JACK_SERVER_VM_ARGUMENTS:-Dfile.encodingUTF-8 -XX:TieredCompilation } # 改为 JACK_SERVER_VM_ARGUMENTS${JACK_SERVER_VM_ARGUMENTS:-Dfile.encodingUTF-8 -XX:TieredCompilation -Xmx4096m }血泪经验-Xmx4096m和-Xmx4096M在 Linux JVM 中等价但jack-admin脚本内部用sed解析参数若m为小写sed s/-Xmx[0-9]*m//g会误删m导致参数截断。某导师曾因此调试 17 小时最终发现jack-admin的get_java_options()函数对大小写敏感。建议统一用大写M。修改后必须执行三连击重启服务make clobber # 彻底清除 out/ 目录避免旧 .jack 文件干扰 ./prebuilts/sdk/tools/jack-admin stop-server ./prebuilts/sdk/tools/jack-admin start-server验证方法运行ps aux | grep jack确认存在java -Xmx4096M -Dfile.encodingUTF-8 ... jack-server.jar进程且RSS列 3.8G。4. 编译全流程与避坑指南从lunch到systemimage的 5 个必踩雷区当你完成环境配置进入源码根目录执行source build/envsetup.sh终端会加载lunch函数。此时你以为离system.img只有一步之遥但实际还有 5 个深坑横亘在lunch full_amt6799_evb_n-eng和make -j4 systemimage之间。这些坑不报错却让编译在 78% 处静默失败或生成无法启动的boot.img。以下是某公司 BSP 团队在 3 台不同配置虚拟机上复现并验证的避坑清单。4.1 避坑TAREGT_BRM_PLATFORM is undefined—— 拼写错误引发的雪崩现象执行make -j4 systemimage后首条错误为vendor/amt/libs/hwcomposer.mt6799.1.5.0/Android.mk:4: *** TAREGT_BRM_PLATFORM is undefined. Please make sure the device-vendor.mk is correctly included..且make立即退出不输出任何其他日志。原因TAREGT_BRM_PLATFORM是vendor/amt/libs/hwcomposer.mt6799.1.5.0/Android.mk第 4 行的变量名但正确拼写应为TARGET_BRM_PLATFORMT-A-R-G-E-T非T-A-R-E-G-T。这个 typo 是 MTK 提供的原始源码包中的硬编码错误存在于MT6799_Android_Nougat_7.0.tar.bz2的vendor/amt/目录下。make在解析Android.mk时因变量名非法直接 abort不会继续加载device/amt/amt6799_evb_n/device-vendor.mk。解决手动修正拼写vim vendor/amt/libs/hwcomposer.mt6799.1.5.0/Android.mk # 将第 4 行$(warning TAREGT_BRM_PLATFORM is $(TAREGT_BRM_PLATFORM)) # 改为$(warning TARGET_BRM_PLATFORM is $(TARGET_BRM_PLATFORM)) # 将第 5 行ifeq ($(TAREGT_BRM_PLATFORM),) # 改为ifeq ($(TARGET_BRM_PLATFORM),) # 将第 6 行$(error TAREGT_BRM_PLATFORM is undefined. Please make sure the device-vendor.mk is correctly included.) # 改为$(error TARGET_BRM_PLATFORM is undefined. Please make sure the device-vendor.mk is correctly included.)注意此文件在make clobber后不会被清除因此只需修改一次。若后续make又报此错说明你修改的是备份文件如Android.mk.bak请确认编辑的是原始路径。4.2 避坑ninja: build stopped: subcommand failed——jack服务未真正启动现象make -j4 systemimage运行至out/target/common/obj/JAVA_LIBRARIES/阶段突然中断错误为build/core/ninja.mk:148: recipe for target ninja_wrapper failed make: *** [ninja_wrapper] Error 1且ninja日志为空。原因jack-admin start-server命令返回0但jack进程实际未监听localhost:8075。常见于1JACK_SERVER_COMMAND修改后未执行make clobber旧jack进程仍持有端口2/tmp/jack目录权限为root普通用户无法写入3TMPDIR环境变量指向空间不足的分区。解决强制终止所有jack进程pkill -f jack-server rm -rf /tmp/jack*清理jack数据目录rm -rf ~/.jack-server重新设置TMPDIR并启动export TMPDIR/home/ql/tmp # 确保该目录 ext4 格式且可用空间 50G mkdir -p $TMPDIR ./prebuilts/sdk/tools/jack-admin start-server验证端口netstat -tuln | grep :8075 # 必须输出 tcp6 0 0 :::8075 :::* LISTEN4.3 避坑fatal: fork: Cannot allocate memory——ulimit -u的隐形天花板现象make -j4运行至frameworks/base模块ninja突然报fatal: fork: Cannot allocate memorydmesg显示Out of memory: Kill process 12345 (cc1plus) score 892 or sacrifice child。原因ulimit -u最大用户进程数默认为 32768但make -j4启动的ninja会 fork 出 4 个cc1plus进程每个cc1plus又 fork 出as、ld等子进程峰值进程数超 60000。kernel.pid_max若为默认 32768则fork()失败。解决# 临时提升立即生效 echo 1000000 | sudo tee /proc/sys/kernel/pid_max # 永久生效写入 sysctl.conf echo kernel.pid_max1000000 | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 验证 sysctl kernel.pid_max # 输出 1000000 ulimit -u # 输出 1000000提示此设置需在make前执行且必须在screen或tmux会话中运行make避免终端退出重置ulimit。4.4 避坑libhwui.so: No such file or directory——out/目录残留的幽灵文件现象make -j4 systemimage成功但烧录后设备卡在 bootanimationadb logcat显示FATAL EXCEPTION: main Process: system_server, java.lang.UnsatisfiedLinkError: dlopen failed: library libhwui.so not found。原因make clobber未彻底清理out/target/product/amt6799_evb_n/obj/SHARED_LIBRARIES/下的libhwui_intermediates/目录。该目录包含libhwui.so的中间.o文件但make因jack错误跳过了最终链接步骤导致system/lib/中无libhwui.so。解决# 彻底删除 out/ 目录比 make clobber 更暴力 rm -rf out/ # 重新初始化 source build/envsetup.sh lunch full_amt6799_evb_n-eng # 执行完整编译禁用并行以定位问题 make -j1 systemimage4.5 避坑JDK tool 工具报错—— 多源码共用prebuilts/的符号污染现象在同一虚拟机中解压MT6799_Android_Nougat_7.0.tar.bz2和MT6779_Android_Nougat_7.0.tar.bz2编译 MT6799 时提示prebuilts/sdk/tools/jack.jar: invalid LOC header (bad signature)。原因prebuilts/sdk/tools/目录被两个源码树共享jack.jar文件在解压时被覆盖为 MT6779 版本SHA256 不同而 MT6799 的build/core/config.mk要求jack.jar的MANIFEST.MF中Built-By: MTK-2017Q3否则拒绝加载。解决# 为每个源码树创建独立 prebuilts 符号链接 cd /home/ql/mt6799_src/ rm -rf prebuilts ln -s /home/ql/prebuilts_mt6799 prebuilts cd /home/ql/mt6779_src/ rm -rf prebuilts ln -s /home/ql/prebuilts_mt6779 prebuilts # 分别解压各自 prebuilts cd /home/ql/prebuilts_mt6799/ tar zxvf /mnt/hgfs/share/MT6799_prebuilts.tar.gz cd /home/ql/prebuilts_mt6779/ tar zxvf /mnt/hgfs/share/MT6779_prebuilts.tar.gz教训永远不要在同一个~/下解压多个 MTK 平台源码。某公司曾因此导致 3 个产品线编译全部失败回滚耗时 42 小时。5. 编译产物验证与烧录技巧如何用fastboot确认systemimage真正可用编译成功生成out/target/product/amt6799_evb_n/system.img后别急着fastboot flash system system.img。MT6799 的system.img是 ext4 格式但 MTK 的mkuserimg_mtk.sh脚本在 Ubuntu 16.04 上默认生成sparse格式.img后缀而fastboot要求ext4格式才能正确识别分区大小。直接烧录 sparse image 会导致system分区被截断设备启动后反复重启。以下是经过 12 次烧录验证的完整验证链。5.1 验证system.img格式与完整性首先确认system.img是否为 ext4非 sparsefile out/target/product/amt6799_evb_n/system.img # 正确输出out/target/product/amt6799_evb_n/system.img: Linux rev 1.0 ext4 filesystem data, UUID..., volume name system (needs journal recovery) (extents) (large files) (huge files) # 错误输出out/target/product/amt6799_evb_n/system.img: data # 这是 sparse 格式需转换若为 sparse 格式用simg2img转换# 安装 simg2img来自 android-tools-fsutils sudo apt-get install android-tools-fsutils # 转换 simg2img out/target/product/amt6799_evb_n/system.img out/target/product/amt6799_evb_n/system_ext4.img # 验证转换后格式 file out/target/product/amt6799_evb_n/system_ext4.img然后校验system_ext4.img的 ext4 结构# 挂载为 loop 设备只读 sudo mkdir -p /mnt/system_test sudo mount -o loop,ro out/target/product/amt6799_evb_n/system_ext4.img /mnt/system_test # 检查关键文件是否存在且可读 ls -l /mnt/system_test/bin/sh # 应为 -rwxr-xr-x 1 root root ls -l /mnt/system_test/lib/libc.so # 应为 -rwxr-xr-x 1 root root ls -l /mnt/system_test/app/ # 应为 drwxr-xr-x 2 root root # 卸载 sudo umount /mnt/system_test参数说明mount -o loop,ro的ro只读是关键。若用rw挂载e2fsck可能修改system.img的 superblock 时间戳导致fastboot拒绝烧录认为镜像被篡改。5.2fastboot烧录前的设备状态检查MT6799 EVB 板进入 fastboot 模式后必须确认 USB 连接稳定且设备被正确识别# 查看设备必须输出 0123456789ABCDEF fastboot fastboot devices # 检查 bootloader 版本应为 MTK Preloader v1.2 fastboot getvar version-bootloader # 检查分区表确认 system 分区存在且大小合理 fastboot getvar partition-size:system # 正常输出partition-size:system: 0x00800000 # 即 8MB若为 0x00000000 说明分区表损坏若fastboot getvar partition-size:system返回UNKNOWN需先烧录preloader.bin和lk.bin由 MTK 提供fastboot flash preloader preloader_amt6799_evb_n.bin fastboot flash lk lk_amt6799_evb_n.bin fastboot reboot-bootloader5.3 安全烧录指令与回滚机制烧录system.img时必须使用fastboot flash system非fastboot update并启用--disable-verity和--disable-verification参数否则 Android Verified Boot 会因签名不匹配拒绝启动# 烧录 system 分区ext4 格式 fastboot flash system out/target/product/amt6799_evb_n/system_ext4.img # 关键禁用 verity 和 verification开发阶段必需 fastboot --disable-verity --disable-verification flash system out/target/product/amt6799_evb_n/system_ext4.img # 烧录 boot 分区确保 kernel 和 ramdisk 匹配 fastboot flash boot out/target/product/amt6799_evb_n/boot.img # 重启 fastboot reboot验证技巧烧录后首次启动观察串口日志115200 8N1。正常流程为Preloader - LK - Kernel init - init: starting service servicemanager。若卡在init: Starting service surfaceflinger说明libhwui.so未正确加载需回查 4.4 节的out/清理。从那以后我每次make -j4 systemimage完成都强制走一遍file mount fastboot getvar三连验哪怕多花 3 分钟。因为 MT6799 的system.img生成过程有 7 个隐式依赖点build/make/core/Makefile、build/make/core/image.mk、device/amt/amt6799_evb_n/BoardConfig.mk等任何一个被make clobber漏掉都会让fastboot烧录一个“看起来成功、实则无法启动”的镜像。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑