0%

[原创] Ubuntu 18.04 LTS 编译原生 5.1.1 r26_LMY48Y 并刷机 Nexus 6

先说明下本人的软硬件环境:

硬件环境

OS 环境:Ubuntu 18.04.2 LTS X64 Desktop
内核版本:Linux version 4.15.0-51-generic (buildd@lgw01-amd64-059) (gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3))
硬件环境:

  • CPU:Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz (四核心八线程)
  • 内存:16G DDR4 2400 MT/s
  • 硬盘:1T 机械硬盘
  • 带宽:联通 300Mbits

编译 Android 的前提

  • OpenJDK 7 (注意:不能是 Oracal JDK 7)
  • GNU Make 3.81 到 3.82
  • Git 1.7 或更高版本

本人实际软件环境

  • java version “1.7.0_161” OpenJDK 64-Bit
  • Python 2.7.15+
  • GNU Make 3.82
  • git version 2.17.1

下载 Android 源代码

下载 repo 工具:

1
2
3
4
$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo

建立工作目录

1
2
$ mkdir -p ~/android-source/android-5.1.1_r26/
$ cd ~/android-source/android-5.1.1_r26/

修改仓库下载地址

由于众所周知的原因,国内下载 Google 的东西,需要自备梯子。因此需要将下载仓库的地址修改成国内的镜像。我这边使用的是清华大学提供的镜像地址:

1
$ vim ~/bin/repo

将其中的 REPO_URL 修改成清华的镜像地址:

1
REPO_URL = 'https://gerrit-google.tuna.tsinghua.edu.cn/git-repo'

初始化 Git 账号

1
2
$ git config --global user.email <your email>
$ git config --global user.name <your name>

初始化仓库

1
2
3
4
$ cd ~/android-source/android-5.1.1_r26/
$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest
#
$ repo init -u git://aosp.tuna.tsinghua.edu.cn/aosp/platform/manifest

使用特别 Android 版本初始化仓库

1
2
$ cd ~/android-source/android-5.1.1_r26/
$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-5.1.1_r26

同步源码

1
2
$ cd ~/android-source/android-5.1.1_r26/
$ repo sync

同步代码会花费很长时间,是拼网速的时候了。我大概下了 9 个小时左右。

查看 Android 系统的版本号

1
2
$ cd ~/android-source/android-5.1.1_r26/
$ cat build/core/version_defaults.mk

编译原生代码

编译 make 3.82

Ubuntu 自带的 make 版本是 4,而编译 Android 5.1.1 需要 3.81 或 3.82。因此首先需要先编译特定版本的 make
本人编译的是 3.82 版本的 make 方法如下:

1
2
3
4
5
6
7
$ wget ftp://ftp.gnu.org/gnu/make/make-3.82.tar.gz
$ cd /opt/
$ sudo tar zxvf ~/Downloads/make-3.82.tar.gz
$ cd make-3.82/
$ ./configure
$ sudo make
$ sudo make install

如果编译过程中,遇到 “alloca 问题”,可按如下方法解决:

1
vim /opt/make-3.82/glob/glob.c

添加一行代码 #define alloca alloca
添加前:

1
2
3
#if defined _AIX && !defined __GNUC__
#pragma alloca
#endif

添加后:

1
2
3
4
#define __alloca alloca              
#if defined _AIX && !defined __GNUC__
#pragma alloca
#endif

编译成功后,会看到如下提示:

1
2
3
4
5
6
7
8
9
10
11
......
make[2]: Leaving directory '/opt/make-3.82/doc'
make[1]: Leaving directory '/opt/make-3.82/doc'
make[1]: Entering directory '/opt/make-3.82'
make[2]: Entering directory '/opt/make-3.82'
test -z "/usr/local/bin" || /bin/mkdir -p "/usr/local/bin"
/usr/bin/install -c make '/usr/local/bin'
test -z "/usr/local/share/man/man1" || /bin/mkdir -p "/usr/local/share/man/man1"
/usr/bin/install -c -m 644 make.1 '/usr/local/share/man/man1'
make[2]: Leaving directory '/opt/make-3.82'
make[1]: Leaving directory '/opt/make-3.82'

新的 make 会被放到如下位置:
/usr/local/bin/
建议在编译 Android 时,将该版本的 make 设置成默认的 make,需要将该版本的版本复制到 /usr/bin/ 下面。(别忘了备份原来版本的 make

1
2
$ sudo mv /usr/bin/make /usr/bin/make.bak
$ sudo cp /usr/local/bin/make /usr/bin/

编译结束后,将 make 文件还原成原来的版本:

1
2
3
$ sudo mv /usr/bin/make /usr/bin/make-3.82.bak
$ sudo mv /usr/bin/make.bak /usr/bin/make
$ sudo mv /usr/local/bin/make /usr/local/bin/make-3.82.bak

安装 openjdk-7

下载 openjdk-7 及依赖包

以下依赖包需要根据你的系统环境,下载对应的版本。我这边下载的是 amd64 版本

  1. 官网地址 openjdk-7-jdk 下载地址 amd64 版本
  2. 官网地址 openjdk-7-jre 下载地址 amd64 版本
  3. 官网地址 openjdk-7-jre-headless 下载地址 amd64 版本
  4. 官网地址 libjpeg62-turbo 下载地址 amd64 版本
  5. 官网地址 libfontconfig1 下载地址 amd64 版本
  6. 官网地址 fontconfig-config 下载地址 amd64 版本
安装

先安装依赖包,最后安装 openjdk-7-jdk。

1
2
3
4
5
6
$ sudo dpkg -i fontconfig-config_2.13.1-2_all.deb
$ sudo dpkg -i libfontconfig1_2.13.1-2_amd64.deb
$ sudo dpkg -i libjpeg62-turbo_1.5.2-2+b1_amd64.deb
$ sudo dpkg -i openjdk-7-jre-headless_7u161-2.6.12-1_amd64.deb
$ sudo dpkg -i openjdk-7-jre_7u161-2.6.12-1_amd64.deb
$ sudo dpkg -i openjdk-7-jdk_7u161-2.6.12-1_amd64.deb
配置

安装完后,需要进行基本的配置。配置方法很多,大家自行百度即可。

一定要保证执行 javajavac 时,使用的是刚刚安装的版本。

1
2
3
4
5
6
$ java -version
java version "1.7.0_161"
OpenJDK Runtime Environment (IcedTea 2.6.12) (7u161-2.6.12-1)
OpenJDK 64-Bit Server VM (build 24.161-b01, mixed mode)
$ javac -version
javac 1.7.0_161

下载编译 Andriod 所需的依赖包

1
2
3
4
5
6
7
8
$ sudo apt install mingw-w64
$ sudo apt-get install git gnupg flex bison gperf build-essential zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 libgl1-mesa-dev g++-multilib tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
$ sudo apt-get install libc6-dev-amd64
$ sudo apt-get install bison
$ sudo apt-get install g++-multilib
$ sudo apt-get install zlib1g-dev
$ sudo apt-get install libswitch-perl
$ sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so

真机驱动

下载驱动

因为我们需要将 Android 5.1.1 刷到 Nexus 6 中。因此需要下载 Google 驱动程序。Nexus 6 对应的 Code Name 是 shamu,Android 5.1.1 r26 对应的细分版本是 LMY48Y

我下载了如下三个必要驱动:

您可以查看更多关于 代号、标签和版本号 的信息。

安装驱动并取得 vendor 文件夹

解压缩上面下载的驱动并执行命令:

1
2
3
4
5
6
7
8
9
10
11
12
$ cd ~/android-source/
$ mkdir 'drivers-Nexus 6 (Mobile) binaries for Android 5.1.1 (LMY48Y)'
$ wget https://dl.google.com/dl/android/aosp/broadcom-shamu-lmy48y-d55a6fcd.tgz
$ wget https://dl.google.com/dl/android/aosp/moto-shamu-lmy48y-df4284cc.tgz
$ wget https://dl.google.com/dl/android/aosp/qcom-shamu-lmy48y-6d077370.tgz
$ tar xvf broadcom-shamu-lmy48y-d55a6fcd.tgz
$ tar xvf moto-shamu-lmy48y-df4284cc.tgz
$ tar xvf qcom-shamu-lmy48y-6d077370.tgz
# 执行如下三个命令时,按提示需要输入 "I ACCEPT"
$ ./extract-broadcom-shamu.sh
$ ./extract-moto-shamu.sh
$ ./extract-qcom-shamu.sh

执行完上面的命令后,会得到 vendor 文件夹。

移动 vendor 文件夹自源码目录
1
2
$ cd ~/android-source/android-5.1.1_r26/
$ cp -r ../drivers-Nexus\ 6\ \(Mobile\)\ binaries\ for\ Android\ 5.1.1\ \(LMY48Y\)/vendor/ .

解决潜在的问题

在编译 Android 源代码过程中,很可能是会遇到各种各样的问题,为了减少出现可能,请按如下可能出现的问题中提到的解决办法,提前进行疏通。

Q1

编译代码时,可能会遇到如下问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
......
including ./system/vold/Android.mk ...
including ./tools/external/fat32lib/Android.mk ...
host Java: doclava (out/host/common/obj/JAVA_LIBRARIES/doclava_intermediates/classes)
target Java: conscrypt (out/target/common/obj/JAVA_LIBRARIES/conscrypt_intermediates/classes)
Install: out/host/linux-x86/framework/jarjar.jar
target Java: ext (out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes)
Lex: aidl <= frameworks/base/tools/aidl/aidl_language_l.l
Copying: out/target/common/obj/JAVA_LIBRARIES/core-junit_intermediates/classes-jarjar.jar
flex-2.5.39: loadlocale.c:130:_nl_intern_locale_data: ?? 'cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' ???
Copy: rmtypedefs (out/host/linux-x86/obj/EXECUTABLES/rmtypedefs_intermediates/rmtypedefs)
host C++: libaapt_32 <= frameworks/base/tools/aapt/ResourceIdCache.cpp
host C++: libaapt_32 <= frameworks/base/tools/aapt/ResourceTable.cpp
host C++: libaapt_32 <= frameworks/base/tools/aapt/SourcePos.cpp
make: *** [out/host/linux-x86/obj32/EXECUTABLES/aidl_intermediates/aidl_language_l.cpp] 已放弃 (core dumped)
make: *** 正在等待未完成的任务....
host C++: libaapt_32 <= frameworks/base/tools/aapt/StringPool.cpp
注: 某些输入文件使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
注: 某些输入文件使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
注: 某些输入文件使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
注: 某些输入文件使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
注: 某些输入文件使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
make: *** wait: 没有子进程。 停止。

执行如下代码即可:

1
2
$ cd ~/android-source/android-5.1.1_r26/
$ export LC_ALL=C
Q2

编译代码时,可能会遇到如下问题:

1
2
3
4
5
6
7
8
9
10
......
libnativehelper/JniInvocation.cpp:165: error: unsupported reloc 43
libnativehelper/JniInvocation.cpp:165: error: unsupported reloc 43
libnativehelper/JniInvocation.cpp:165: error: unsupported reloc 43
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [out/host/linux-x86/obj32/lib/libnativehelper.so] Error 1
make: *** Waiting for unfinished jobs....
host C++: libc++ <= external/libcxx/src/exception.cpp
host StaticLib: libc++abi_32 (out/host/linux-x86/obj32/STATIC_LIBRARIES/libc++abi_intermediates/libc++abi.a)
Command exited with non-zero status 2

需要执行如下命令:

1
2
3
$ cd ~/android-source/android-5.1.1_r26/
$ mv prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6/x86_64-linux/bin/ld prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6/x86_64-linux/bin/ld.bak
$ cp /usr/bin/ld.gold prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6/x86_64-linux/bin/ld
Q3

编译代码时,可能会遇到如下问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
......
out/target/common/obj/PACKAGING/public_api.txt:116: error 5: Added public field android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST
Checking API: checksystemapi-last
Checking API: checksystemapi-current
Copying: out/target/common/obj/JAVA_LIBRARIES/mms-common_intermediates/classes.jar
Copying: out/target/common/obj/APPS/Bluetooth_intermediates/noproguard.classes.jar
target Symbolic: libaudioutils (out/target/product/generic/symbols/system/lib/libaudioutils.so)
target SharedLib: libbacktrace (out/target/product/generic/obj/SHARED_LIBRARIES/libbacktrace_intermediates/LINKED/libbacktrace.so)
target Symbolic: libcamera_metadata (out/target/product/generic/symbols/system/lib/libcamera_metadata.so)
target Symbolic: libhardware (out/target/product/generic/symbols/system/lib/libhardware.so)

******************************
You have tried to change the API from what has been previously approved.

To make these errors go away, you have two choices:
1) You can add "@hide" javadoc comments to the methods, etc. listed in the
errors above.

2) You can update current.txt by executing the following command:
make update-api

To submit the revised current.txt to the main Android repository,
you will need approval.
******************************

make: *** [out/target/common/obj/PACKAGING/checkpublicapi-current-timestamp] Error 38
make: *** Waiting for unfinished jobs....
Command exited with non-zero status 2

需要执行如下命令:

1
2
$ cd ~/android-source/android-5.1.1_r26/
$ make update-api

编译源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ cd ~/android-source/android-5.1.1_r26/
# 初始化环境变量
$ . build/envsetup.sh
# 选择平台编译选项
$ lunch
You're building on Linux

Lunch menu... pick a combo:
1. aosp_arm-eng
2. aosp_arm64-eng
3. aosp_mips-eng
4. aosp_mips64-eng
5. aosp_x86-eng
6. aosp_x86_64-eng
7. aosp_manta-userdebug
8. aosp_deb-userdebug
9. full_fugu-userdebug
10. aosp_fugu-userdebug
11. aosp_flo-userdebug
12. aosp_tilapia-userdebug
13. aosp_grouper-userdebug
14. aosp_flounder-userdebug
15. aosp_shamu-userdebug
16. mini_emulator_arm64-userdebug
17. mini_emulator_x86-userdebug
18. mini_emulator_x86_64-userdebug
19. m_e_arm-userdebug
20. mini_emulator_mips-userdebug
21. aosp_mako-userdebug
22. aosp_hammerhead-userdebug

Which would you like? [aosp_arm-eng]

根据真机驱动中的内容,我们这里需要输入 15 选择 aosp_shamu-userdebug 并按回车键确认。

执行如下命令,开始正式编译 Android 源代码:

1
$ make -j8

说明

-j 后面的数字,用于指定并行任务的数量。通常是 CPU 核数的一或两倍。

若编译成功,会看到如下 Log:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
......
target Strip: libwebviewchromium (out/target/product/shamu/obj/lib/libwebviewchromium.so)
Install: out/target/product/shamu/system/lib/libwebviewchromium.so
Install: out/target/product/shamu/system/app/webview/webview.apk
mkdir -p out/target/product/shamu/system/app/webview/lib/arm ;ln -sf /system/lib/libwebviewchromium.so out/target/product/shamu/system/app/webview/lib/arm/libwebviewchromium.so
Install: out/target/product/shamu/system/priv-app/Settings/Settings.apk
build/tools/generate-notice-files.py out/target/product/shamu/obj/NOTICE.txt out/target/product/shamu/obj/NOTICE.html "Notices for files contained in the filesystem images in this directory:" out/target/product/shamu/obj/NOTICE_FILES/src
Combining NOTICE files into HTML
Combining NOTICE files into text
Installed file list: out/target/product/shamu/installed-files.txt
Target system fs image: out/target/product/shamu/obj/PACKAGING/systemimage_intermediates/system.img
Running: mkuserimg.sh -s out/target/product/shamu/system out/target/product/shamu/obj/PACKAGING/systemimage_intermediates/system.img ext4 system 2130538496 out/target/product/shamu/root/file_contexts
make_ext4fs -s -T -1 -S out/target/product/shamu/root/file_contexts -l 2130538496 -a system out/target/product/shamu/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/shamu/system
Creating filesystem with parameters:
Size: 2130538496
Block size: 4096
Blocks per group: 32768
Inodes per group: 8128
Inode size: 256
Journal blocks: 8127
Label:
Blocks: 520151
Block groups: 16
Reserved block group size: 127
Created filesystem with 1782/130048 inodes and 154288/520151 blocks
build_verity_tree -A aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7 out/target/product/shamu/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmpnMFZT5_verity_images/verity.img
system/extras/verity/build_verity_metadata.py 2130538496 /tmp/tmpnMFZT5_verity_images/verity_metadata.img 86e77c8ceac2d4248a46ad18979b2ddaf51c0a1889ff8b22ae39bef55abc77c8 aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7 /dev/block/platform/msm_sdcc.1/by-name/system out/host/linux-x86/bin/verity_signer build/target/product/security/verity.pk8
append2simg out/target/product/shamu/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmpnMFZT5_verity_images/verity_metadata.img
append2simg out/target/product/shamu/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmpnMFZT5_verity_images/verity.img
Install system fs image: out/target/product/shamu/system.img
out/target/product/shamu/system.img+out/target/product/shamu/obj/PACKAGING/recovery_patch_intermediates/recovery_from_boot.p maxsize=2192424960 blocksize=135168 total=615381140 reserve=22167552

#### make completed successfully (47:32 (mm:ss)) ####

编译完之后,会多出一个 out 文件夹,大小为 28G。编译生成的镜像文件位置:

1
~/android-source/android-5.1.1_r26/out/target/product/shamu/system.img

该文件大小为 587M。

而编译之后的整个 ~/android-source/android-5.1.1_r26/ 文件夹大小为 109G。

刷写 Nexus 6 设备

解锁引导加载程序

只有在引导加载程序允许的情况下,您才可以刷写定制系统,而引导加载程序默认处于锁定状态。您可以解锁引导加载程序,但这样做会导致系统出于隐私原因而删除用户数据。解锁之后,系统会清空设备上的所有数据,即应用中的个人数据以及可通过 USB 访问的共享数据(包括照片和影片)。请先备份设备上的所有重要文件,然后再尝试解锁引导加载程序。

您只需解锁引导加载程序一次,并可视需要将其重新锁定。

解锁新款设备

自 2014 年以来发布的所有 Nexus 和 Pixel 设备(从 Nexus 6 和 Nexus 9 开始)都内置有恢复出厂设置保护功能,需要执行多个步骤才能解锁引导加载程序。

  1. 要在设备上启用 OEM 解锁功能,请执行以下操作:

    1. 在“设置”中,点按关于手机,然后点按版本号七 (7) 次。
    2. 当看到“您已处于开发者模式”这条消息后,点按返回按钮。
    3. 点按开发者选项,然后启用 OEM 解锁USB 调试(如果 OEM 解锁处于停用状态,请连接到互联网,以便设备可以至少签到一次。如果“OEM 解锁”仍处于停用状态,则说明设备可能已被运营商锁定 SIM 卡,系统无法解锁引导加载程序)。
  2. 重新启动进入引导加载程序,然后使用 fastboot 解锁。

    • 对于新款设备(2015 年及之后发布的设备):

      1
      $ fastboot flashing unlock
    • 对于老款设备(2014 年及之前发布的设备):

      1
      $ fastboot oem unlock
  3. 在屏幕上确认解锁。

重新锁定引导加载程序

要重新锁定引导加载程序,请执行以下命令:

  • 对于新款设备(2015 年及之后发布的设备):

    1
    $ fastboot flashing lock
  • 对于老款设备(2014 年及之前发布的设备):

    1
    $ fastboot oem lock

    由于我这台设备已经处于解锁状态,所以以上步骤并未经过验证。

进入 fastboot 模式

根据官方文档的提示,先将手机关机,之后同时按住电源键和音量调低键,进入 fastboot 模式。

fastboot

刷写设备

之前编译完源代码之后,会多出一个 out 文件夹,生产的镜像文件都在这里。执行如下命令,开始刷写镜像:

1
$ cd ~/android-source/android-5.1.1_r26/out/target/product/shamu/
1
2
3
4
5
6
7
$ fastboot flash recovery recovery.img
target reported max download size of 536870912 bytes
sending 'recovery' (8337 KB)...
OKAY [ 0.263s]
writing 'recovery'...
OKAY [ 0.159s]
finished. total time: 0.422s
1
2
3
4
5
6
7
$ fastboot flash boot boot.img
target reported max download size of 536870912 bytes
sending 'boot' (7745 KB)...
OKAY [ 0.244s]
writing 'boot'...
OKAY [ 0.114s]
finished. total time: 0.358s
1
2
3
4
5
6
7
8
9
10
11
$ fastboot flash system system.img
target reported max download size of 536870912 bytes
sending sparse 'system' (518573 KB)...
OKAY [ 16.363s]
writing 'system'...
OKAY [ 7.690s]
sending sparse 'system' (81766 KB)...
OKAY [ 2.589s]
writing 'system'...
OKAY [ 1.365s]
finished. total time: 28.006s

以下两个镜像可根据需要选择性的进行刷新。若刷新 cache.imguserdata.img 的话,原手机的里内容会被清空。

1
2
3
4
5
6
7
8
9
$ fastboot flash cache cache.img
target reported max download size of 536870912 bytes
erasing 'cache'...
OKAY [ 0.029s]
sending 'cache' (6248 KB)...
OKAY [ 0.198s]
writing 'cache'...
OKAY [ 0.111s]
finished. total time: 0.338s
1
2
3
4
5
6
7
8
9
10
11
$ fastboot flash userdata userdata.img
target reported max download size of 536870912 bytes

erasing 'userdata'...
OKAY [ 1.181s]
sending 'userdata' (139036 KB)...
OKAY [ 4.354s]
writing 'userdata'...
OKAY [ 2.616s]
finished. total time: 8.151s

最后重启手机:

1
2
3
4
$ fastboot reboot
rebooting...

finished. total time: 0.151s

刷机后查看设备信息:

About Phone

参考文献

  1. 在Ubuntu 18.04.1系统中安装Jdk 7(openjdk-7-jdk)
  2. Ubuntu 下 Nexus 6 保留数据线刷 Android 5.1.1
坚持原创及高品质技术分享,您的支持将鼓励我继续创作!