QUIC协议
QUIC, a multiplexed stream transport over UDP 是Chromium使用的通信协议,是基于UDP实现的类似于 TCP+TLS+HTTP/2 的协议。也是HTTP 3.0的设计方案。有兴趣的话大家可参考文档: Playing with QUIC
Chromium项目是开源的,The Chromium Projects(http://dev.chromium.org/chromium-projects) 文档详细介绍了Chromium项目的实现原理,以及如何获取源码并进行编译。
Cronet 库是Chrome使用的移动端网络库。支持 HTTP、HTTP/2 以及 QUIC 协议。支持 Android 和 iOS 平台。 其编译工具是 gn 和 ninja,类似于 cmake 与 make 的关系。 下面介绍 Cronet 库的编译及编译注意事项。
获取Chromium源码
可以参考官方文档:Checking out and building Chromium for Mac
获取源码之前,首先需要下载安装 depot_tools 工具。在一个适当的目录下clone depot_tools包:
1 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git |
将depot_tools
的路径(最好是绝对路径,~
需替换为$HOME
)加进环境变量PATH中,假设 depot_tools
工程在/path/to/depot_tools
目录下:
1 | export PATH=$PATH:/path/to/depot_tools |
如果从来没有下载过Chromium的代码的话,为源码创建一个文件夹并下载源码:
1 | mkdir chromium && cd chromium |
–no-history
可以节省代码下载时间,它忽略仓库的历史信息;整个代码量较大,约 14G,且需要翻墙,1M 左右的速度需要 20~30 分钟。若中间拉取失败,可以执行 gclient sync
继续拉取, 拉取结束后,该目录会生成一个 src 目录,包含 cronet 源码。
获取源码是很漫长的过程,Chromium项目的源码有8G。我花了2个半小时才完成。中途遇到了download_from_google_storage.py 下载文件没反应的问题,参考了Chromium的源码获取与编译(2018-06-06)
最终chromium/src
代码大小如下:
1 | du -d 1 -h | sort -h |
命令行翻墙,需要使用 http proxy 配置:
1 | export http_proxy=http://127.0.0.1:8118 |
启动 privoxy 转换 socks5 为 http proxy:1
privoxy --no-daemon /usr/local/etc/privoxy/config
编译Cronet
Cronet的源码位于 src/components/cronet
目录,官方编译流程可参考Cronet build instructions,编译环境要求:
- Linux:python 2.7.5,及 jdk 8,较高版本由于接口不兼容需避免使用。
- Mac: python 2.7.5,jdk 8,以及 xcode。 进入 chromium/src 目录,执行下面命令
Android / iOS builds
1 | ./components/cronet/tools/cr_cronet.py gn --out_dir=out/Cronet # 生成 ninja 文件 |
如果主机是linux,build的是Android的库。如果主机是MacOS,build的是ios库。以下命令在Mac上会生成 cronet 静态库,目录 obj/components/cronet/ios/libcronet*.a
Desktop builds (targets the current OS)
1 | gn gen out/Cronet |
Running the ninja files
输入 ninja 文件执行编译,必须指定为 cronet_package
1 | ninja -C out/Cronet cronet_package |
这个命令会编译 cronet 模块,及其依赖的所有模块,包括base,crypto,boringssl,protobuf,url等。编译Cronet库,最终文件可以在out/Cronet/cornet
中寻找。
生成的文件
iOS 库:
- out/MyCronet/obj/components/cronet/ios/libcronet.a, 大小为 89M;
- out/MyCronet/obj/components/cronet/ios/libcronet_static.a, 大小为 17M;
- out/MyCronet/obj/components/cronet/ios/libcronet_deps_complete.a,大小为 1G。
Android 库:
- out/Cronet-android/lib.java/components/cronet/android/ 所有 jar 包在此目录下,一般不用;
- out/Cronet-android/cronet/ 需要使用cronet库的java API的so、及jar包都在此目录下;
- out/Cronet-android/libcronet.77.0.3825.0.so,strip 后的库,6M;
- out/Cronet-android/lib.unstripped,未 strip 的库在此目录下。50.9M;
- out/Cronet-android/gen/components/cronet/android/cronet_jni_registration.h,该文件便是自动生成的JNI头文件
使用Cronet
Debug Log
C++层的日志可以通过 adb logcat
输出. 但是默认只显示 FATAL 级别的日志。如果想要更改日志输出级别,可以通过以下命令打开chromium日志输出:
See VLOG(1) and VLOG(2) logging:
1 | adb shell setprop log.tag.CronetUrlRequestContext VERBOSE |
See VLOG(1) logging:
1 | adb shell setprop log.tag.CronetUrlRequestContext DEBUG |
See NO (only FATAL) logging:
1 | adb shell setprop log.tag.CronetUrlRequestContext NONE |
Network Log
NetLog 是 Chromium 网络模块的日志:NetLog: Chrome’s network logging system。可以使用下面两行代码操作 dump 出 chromium 网络模块的日志:
1 | CronetEngine.startNetLogToFile() |
Chromium网络模块的日志输出内容是 JSON 格式的,所以需要主动调用 stopNetLog()
方法保证 JSON日志的完整性。
导出的log文件可以使用 https://netlog-viewer.appspot.com/#import 分析。如果打不开,可以使用 Chromium NetLog dump viewer 这个Chrome扩展程序。
GN语法
参考 GN Quick Start guide 和 GN Language and Operation,建议大家先了解下target的概念,因为gn命令操作的基本上都是target。
1 | // 列出指定构建目录下所有的targets |
Cronet request lifecycle
1 | ninja -help |