3)、双击 Breakpoints Settings 面板中的目标
URL,在弹出的 Edit Breakpoint 面板中进行编辑。
4)、这里默认选择断点 Request 与 Response,我们可以选择仅断点 Response 或 Request。点击确认即断点设置完成。
5)、然后,我们就可以点击主面板右侧的 Edit Response 编辑 Response,修改完成后点击最下方的 Execute 即可。
使用 Map Local
1)、自由模拟服务端的返回数据,以提前进行接口测试。
1)、右键点击要使用 Map Local 的 URL,选中Map Local 开启断点功能。
1)、然后,我们在 Edit Mapping 面板中选择 Map To 的 Local path,选择本地设定的 maplocal 本地数据(例如 JsonString)
弱网模拟功能
-
1)、注意开启前需将 Map Local 关闭。
-
2)、点击 Proxy => Throttle Setting => 选中 Enable Throttling
-
3)、这里预设了很多模拟设置,我们只需将 网络包传输的速率 Throttle preset 设置为较低的速率(一般设为 256/512)。
碰到的问题
- 1)、注意手机与笔记本电脑需要同一 WIFI 下,不能自己开热点或使用公司内网,否则无法在 电脑端 无法弹出手机连接 Charles 的提示确认框,并且也无法下载 Charles 提供的 SSL 证书。
- 2)、手机端下载 Charles 提供的 SSL 证书时最好不使用系统浏览器访问。
3、Wireshark
强烈推荐 geektime-webprotocol
WireShark 主要可以用来对四种流进行跟踪,如下所示:
- TCP
- UDP
- SSL
- HTTP
1)、WireShark 基本使用
如何捕获报文
- 1)、点击捕获->选项,打开捕获窗口
- 网卡设备/流量/捕获过滤器,点击“开始”按钮开始抓包
- 输出(指定缓存文件)/选项(显示、名称解析、自动停止抓包条件) 面板
- 2)、点击捕获->停止,停止抓包
Wireshark 面板
快捷方式工具栏
数据包的颜色(视图->着色规则)
设定时间显示格式
数据包列表面板的标记符号
文件操作
- 1)、标记报文 Ctrl+M。
- 2)、导出标记报文(文件->导出特定分组),亦可按过滤器导出报文 ,
- 3)、合并读入多个报文(文件->合并)。
如何快速抓取移动设备的报文?
- 1、打开手机的 wifi 热点。
- 2、电脑连接手机的 wifi 热点。
- 3、用 Wireshark 打开捕获->选项面板,选择 wifi 热点对应的接口设备抓包即可。
2)、Wireshark 过滤器
如果表达式的背景为绿色,则说明过滤器的语法是正确的,红色则说明有错误。
捕获过滤器
它用于减少抓取的报文体积,使用 BPF(Berkeley Packet Filter) 语法,功能相对有限。
BPF 可以在设备驱动级别提供抓包过滤接口,多数抓包工具都支持此语法。而 BPF 的 Expression 表达式由多个 primitives 原语组成。而每一个 primitives 原语则由名称或数字,以及描述它的多个 qualifiers 限定词组成。
qualifiers 限定词
- 1、Type:设置数字或者名称所指示类型
- host、port。
- net ,设定子网,net 192.168.0.0 mask 255.255.255.0 等价于 net 192.168.0.0/24。
- portrange,设置端口范围,例如 portrange 6000-8000。
- 2、Dir:设置网络出入方向
- src、dst、src or dst、src and dst。
- ra、ta、addr1、addr2、addr3、addr4(仅对 IEEE 802.11 Wireless LAN 有效)。
- 3、Proto:指定协议类型
- ether、fddi、tr、 wlan、
- ip、 ip6、 arp、 rarp、
- decnet、 tcp、udp、icmp、igmp、icmp
- igrp、pim、ah、esp、vrrp
- 4、其他
- gateway:指明网关 IP 地址,等价于 ether host ehost and not host host。
- broadcast:广播报文,例如 ether broadcast 或者 ip broadcast。
- multicast:多播报文,例如 ip multicast 或者 ip6 multicast。
- less, greater:小于或者大于。
简单示例
src or dst portrange 6000-8000 && tcp or ip6
显示过滤器
它对已经抓取到的报文进行过滤显示,功能强大。
基于协议域过滤
- 捕获所有 TCP 中的 RST 报文:tcp[13]&4==4。
- 抓取 HTTP GET 报文:port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420。(47455420 是 ASCII 码的 16 进制,表示”GET ”)
- 抓取 HTTP POST 报文:port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504F5354
显示过滤器的过滤属性
任何在报文细节面板中解析出的字段名,都可以作为过滤属性。在视图->内部->支持的协议面板里,可以看到各字段名对应的属性名。例如,在报文细节面板中 TCP 协议头中的 Source Port,对应着过滤属性为 tcp.srcport。
常用操作符
- 1)、and(&&):AND 逻辑与,ip.src==10.0.0.5 and tcp.flags.fin。
- 2)、or(||):OR 逻辑或,ip.scr10.0.0.5 or ip.src192.1.1.1。
- 3)、xor(^^):XOR 逻辑异或,tr.dst[0:3] == 0.6.29 xor tr.src[0:3] == 0.6.29。
- 4)、not(!):NOT 逻辑非,not llc。
- 5)、[…]:中括号[]Slice 切片操作符
- [n:m]表示 n 是起始偏移量,m 是切片长度,例如:eth.src[0:3] == 00:00:83
- [n-m]表示 n 是起始偏移量,m 是截止偏移量,例如:eth.src[1-2] == 00:83
- [:m]表示从开始处至 m 截止偏移量,例如:eth.src[:4] == 00:00:83:00
- [m:]表示 m 是起始偏移量,至字段结尾,例如:eth.src[4:] == 20:20
- [m]表示取偏移量 m 处的字节,例如:eth.src[2] == 83
- [,]使用逗号分隔时,允许以上方式同时出现,例如:eth.src[0:3,1-2,:4,4:,2] ==00:00:83:00:83:00:00:83:00:20:20:83
- 6)、in:大括号{}集合操作符,例如 tcp.port in {443 4430…4434} ,实际等价于 tcp.port == 443 || (tcp.port >= 4430 && tcp.port ⇐ 4434)。
可用函数
- upper:将字符串字段转换为大写。
- lower:将字符串字段转换为小写。
- len:返回字符串或字节数组的字节长度。
- count:返回在一帧中字段出现的数量。
- string:将非字符串字段转换为字符串。
显示过滤器的可视化对话框
环形缓冲器
例如使用 3 个文件的环形缓存器,从 **.1 => **.2 => **.3 然后又从 **.1 文件开始记录,形成环形。
4、TcpDump(网络数据包嗅探器)
1)、抓包步骤
1、获取 ROOT 权限的手机一部
2、下载 tcpdump
3、将 tcpdump 安装到手机上
adb push tcpdump /data/local/tmp
4、修改 tcpdump 的权限,使其具有可执行的权限
chmod 777 /data/local/tmp/tcpdump
5、执行 tcpdump 命令进行抓包,按组合键 Ctrl + C 可以停止抓包
6、将抓到的数据包的信息保存为 Pcap 文件,这里仅需在执行 tcpdump 后加上 -w 参数
tcpdump-w /data/local/tmp/tcp.pcap
7、把 Pcap 复制到 电脑上,使用 Wireshark 分析数据包的流量。
2)、捕获及停止条件
- -D:列举所有网卡设备。
- -i:选择网卡设备。
- -c:抓取多少条报文。
- –time-stamp-precision:指定捕获时的时间精度,默认毫秒 micro,可选纳秒 nano。
- -s:指定每条报文的最大字节数,默认 262144 字节。
3)、文件操作
- -w:输出结果至文件(可被Wireshark读取分析)。
- -C:限制输入文件的大小,超出后以后缀加 1 等数字的形式递增。 注意单位是 1,000,000 字节。
- -W:指定输出文件的最大数量,到达后会重新覆写第 1 个文件。
- -G:指定每隔N秒就重新输出至新文件,注意-w 参数应基于
strftime 参数指定文件名。
- -r:读取一个抓包文件。
- -V:将待读取的多个文件名写入一个文件中,通过读取该文件同时 读取多个文件。
4)、输出时间戳格式
- -t:不显示时间戳。
- -tt:自1970年1月1日0点至今的秒数。
- -ttt:显示邻近两行报文间经过的秒数。
- -tttt:带日期的完整时间。
- -ttttt:自第一个抓取的报文起经历的秒数。
5)、分析信息详情
- -e:显示数据链路层头部。
- -q:不显示传输层信息。
- -v:显示网络层头部更多的信息,如 TTL、id 等。
- -n:显示 IP 地址、数字端口代替 hostname 等。
- -S:TCP 信息以绝对序列号替代相对序列号。
- -A:以 ASCII 方式显示报文内容,适用 HTTP 分析。
- -x:以 16 进制方式显示报文内容,不显示数据链路层。
- -xx:以 16 进制方式显示报文内容,显示数据链路层。
- -X:同时以 16 进制及 ACII 方式显示报文内容,不显示数据链路层 • -XX 同时以 16 进制及 ACII 方式显示报文内容,显示数据链路层。
5、Stetho
- 1)、在 build.gradle 中,除了 Stetho 依赖外,还需添加 ‘com.facebook.stetho:stetho-okhttp3:1.5.0’。
- 2)、在 Application 的 onCreate 方法中初始化 ‘Stetho.initializeWithDefaults(this)’。
- 3)、调用 OkHttp 的 ‘addNeworkInterceptor’ 方法添加 Stetho 用于收集网络信息而提供的网络拦截器。
- 4)、访问 Chrome 调试页面 ‘chrome://inspect’。
6、其它的性能检测工具
- strace:跟踪 Socket 相关的系统调用。
- netstat:记录多种网络栈和接口统计信息。
- ifconfig:记录接口配置。
- ip:记录网络接口统计信息。
- ping:测试网络连通性。
- traceroute:测试网络路由。
- /proc/net 命令:查看网络统计信息,Android TrafficState 使用了 /proc/net/xt_qtaguid/stats 和 /proc/net/xt_qtaguid/iface_stat_fmt 文件来统计 App 的流量信息。
三、精准获取流量消耗
1、如何判断 App 流量消耗偏高?
- 1)、绝对值看不出高低。
- 2)、对比竞品,相同 Case 对比流浪消耗。
- 3)、异常监控超过正常指标。
2、测试方案
- 1)、打开手机设置 => 流量管理 => 仅允许目标 App 联网
- 2)、可以查找出大多数的问题,但是线上场景线下可能遇不到。
3、线上流量获取方案
1)、TrafficStats
特点
- API 18 以上。
- 记录手机重启以来的数据流量。
API
- getMobileRxBytes():通过蜂窝流量接收到的信息。
- getUidRxBytes(int uid):获取指定 uid 的接收流量。
- getTotalRxBytes():总发送流量。
缺点
无法获取某个时间段内的流量消耗。
2)、NetworkStatsManager
API 23 之后。
特点
- 1)、获取指定时间间隔内的流量信息。
- 2)、获取不同网络类型下的消耗。
NetUtils.getStats
获取指定时间间隔的 蜂窝 + WIFI 流量总信息
4、前后台流量获取方案
问题:线上反馈 App 后天流量消耗大?
只获取一个时间段的流量不够全面。
实现原理
后台定时任务 => 获取时间间隔内流量 => 记录前后台 => 分别计算 => 上报 APM 后台 => 流量治理依据
小结
- 1)、该方案无法获取应用在前后台切换时的流量,因此有一定的误差,但这个误差是可以接受的。
- 2)、结合精细化的流量异常报警针对性的解决后台跑流量的问题。
成功 log 如下所示:
2020-05-11 10:47:55.633 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 193 | lambda$initEventAndData
1
1
1MainActivity] backNetUseData: 4 MB
2020-05-11 10:47:55.646 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 194 | lambda$initEventAndData
1
1
1MainActivity] foreNetUseData: 4 MB
2020-05-11 10:47:55.652 4036-4181/json.chao.com.wanandroid I/WanAndroid-LOG: │ [MainActivity.java | 197 | lambda$initEventAndData
1
1
1MainActivity] totalNetUseData: 8 MB
四、网络请求流量优化
1、常见使用网络的场景
1)、数据压缩
POST 请求 Body 使用 GZip 压缩,同时服务端返回 Body 也使用 GZip 压缩。
2)、图片
- 图片上传前压缩。
- 图片使用策略细化:让 服务端/CDN 云服务器 优先使用缩略图/WebP格式图片。
3)、性能日志上报:批量 + 特定场景上报
APM 相关、单点问题相关。例如埋点数据可以等到某一时机点(例如 开启了 WIFI、数据量过大必须上传一部分时)再上传。
4)、数据缓存
服务端返回加上过期时间,避免每次重新获取。 节约流量且大幅提高数据访问速度,更好的用户体验。
Request 缓存设置
- 1、Pragma:no-cache:去服务器拉取最新的资源,不使用缓存。
- 2、If-Modified-Since:datetime:如果资源在客户端提供的时间后发生改变,服务器会返回新的资源,否则使用缓存。
- 3、If-None-Match:etagvalue:如果资源的标识和服务器的不同,返回新的资源。
当 Request 的头部是 2 和 3 时,如果服务器的资源没有修改,则服务器会返回 HTTP/304 Not Modified,客户端会使用缓存的 Response。
Response 缓存设置
HTTP Response 是否可以缓存是由 Response 的头部控制的,服务器可以通过 Expires 和 Cache-Control 控制 Response 如何在客户端缓存。
Expires
Expires 头部会包含一个日期,即该资源缓存的有效期,客户端有新的相同请求时,如果资源缓存没有过期,则使用缓存资源,服务器不会返回任何东西。
Cache-Control
Cache-Control 可以标明 Response 如何存储及其如何使用,其选项如下所示:
- 1)、public:Response 可以存储在任何 Cache 中,包括共享的 Cache。
- 2)、private:Response 存储在私有 Cache 中,只能被一个用户使用。
- 3)、no-cache:Response 将来不会被使用。
- 4)、no-store:Response 将来不会被使用,也不会写到磁盘上。
- 5)、max-age=#seconds:Response 在设定的时间内可以被重复使用。
- 6)、must-revalidate:和原始服务器确认 Response 是最新后,可以使用缓存。
OKHttp 无网数据缓存实现
POST 在 OKHttp 中默认不会缓存,因为 POST 一般是用来修改数据的。在 Awesome-WanAndroid 中的 HttpModule—cacheInterceptor 中就已经实现了 OKHttp 的无网数据缓存,代码如下所示:
File cacheFile = new File(Constants.PATH_CACHE);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = chain -> {
Request request = chain.request();
if (!CommonUtils.isNetworkConnected()) {
// 无网时强制使用数据缓存,以提升用户体验。
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (CommonUtils.isNetworkConnected()) {
int maxAge = 0;
// 有网络时, 不缓存, 最大保存时长为0
response.newBuilder()
.header(“Cache-Control”, “public, max-age=” + maxAge)
.removeHeader(“Pragma”)
.build();
} else {
// 无网络时,设置超时为4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.header(“Cache-Control”, “public, only-if-cached, max-stale=” + maxStale)
.removeHeader(“Pragma”)
.build();
}
return response;
};
// 缓存优化
builder.addNetworkInterceptor(cacheInterceptor);
builder.addInterceptor(cacheInterceptor);
builder.cache(cache);
5)、离线包、增量数据更新
加上版本的概念,仅传输有变化的数据。
总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的Android开发中高级必知必会核心笔记,共计2968页PDF、58w字,囊括Android开发648个知识点,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。
虽然面试失败了,但我也不会放弃入职字节跳动的决心的!建议大家面试之前都要有充分的准备,顺顺利利的拿到自己心仪的offer。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。
虽然面试失败了,但我也不会放弃入职字节跳动的决心的!建议大家面试之前都要有充分的准备,顺顺利利的拿到自己心仪的offer。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!