1. 什么是 CSMA/CA?
Carrier Sense Multiple Access Collision Avoidance, 载波监听多路访问冲突避免
当 STA 想要发送数据之前,需要对信道进行检测,如果有其他设备在发送,就等待发送完成后再次探测,若信道空闲,则开始发送数据,即冲突避免。
2. WLAN 由什么组成?
- STA
- AP
- IBSS(Independent Basic Service Set, 包含一个及以上的 STA 的无线网络,也叫做 ad-hoc 网络)
- BSS,Basic Service Set,一个 AP 和一个及以上 STA 组成的无线网络,所有 sta 通过 AP 进行通信,AP不仅能链接有线网络,还可以在 STA 之间进行桥接
- ESS,Extended Service Set,扩展服务集,同一有线网络连接的、两个及以上的AP组成
- DS,Distrubution System,分发系统。让 BSS 内的 Ap 通过 DS 互联,STA 可以从一个 BSS 移动到另一个 BSS。AP 之间可以是无限互联,也可以是有线互联,通常是使用有线互联。DS 是 BSS 之间进行逻辑连接基础,让 Sta 在 BSS 之间能够实现漫游
![image]()
3. WLAN 有几种拓扑结构?
一共有两种:
- ad-hoc 模式:两台 sta 之间直接进行无线通信,而组成的网络,也叫做点对点的网络模式,此时 终端不能连接到互联网上。

- 基础设施模式:Infrastructure Mode,802.11 无线网络的 BSS 形式组网,通常是通过 AP 连接到互联网时使用。在这个模式下,除了有 STA 外,还需要有 AP 才能连接到互联网

4. 什么是AP?
Access Point,无线网络的基础设施模式中,通过 AP 设备,把多台终端连接到有线网络中,接入点通常有 RJ 45 网络借口,用来连接到交换机或者路由器上,从而让无线网络的终端可以访问有线网络或互联网。
5. WLAN 有那些标准?
WLAN 标准统称为 802.11, IEEE 802.11 在物理层和数据连路层之间定义了 MAC 子层。定义了 WLAN 采用哪种频带和调制方式,传输速率达到多大等传输标准,还定义了安全性、Qos、管理等相关内容

以上都是 802.11 传输标准,还有一些其他的标准

IEEE 802.11n
IEEE 802.11n 之前的标准已经不多见了,这里就不介绍了。IEEE 802.11n ,又叫做 WiFi 4 ,标准在 2009 年制定完成,最大传输速率是 600 Mbit/s ,使用 MIMO 多通道技术让传输速率大幅提升。也能向下兼容 IEEE 802.11a 、IEEE 802.11b 、IEEE 802.11g 。
IEEE 802.11ac
IEEE 802.11ac ,又叫做 WiFi 5 ,有两个版本,分别是:Wave 1 、Wave 2 。区别是 Wave 1 使用 80 Mhz 频宽和 SU-MIMO 技术,最大传输速率是 3.46 Gbit/s 。而 Wave 2 是使用 160 Mhz 频宽和 DL MU-MIMO 技术,最大传输速率是 6.93 Gbit/s 。频带和调制方式等都相同。
IEEE 802.11ax
IEEE 802.11ax ,又叫做 WiFi 6 ,标准在 2018 年制定完成,最大传输速率是 9.6 Gbit/s 。WiFi 6 同时支持 2.4G 和 5G 频段,完整涵盖低速与高速设备,覆盖范围更远。支持 WPA 3 安全协议,无线网络更安全。支持 TWT 技术,能够更省电。简单的说,就是速度更快、延时更低、容量更低、更安全、更省电。
6. 什么是关联?
使用 WLAN 的终端要通过 AP 完成无线连接,才能访问互联网或有线网络
无线终端连接 AP 的过程叫做 关联(Association)

7. Wifi 测吞吐,UDP能过,TCP不能过,为什么?
描述:一般测吞吐使用 iperf3 命令进行测试
TCP 不能达到标准,可以往一下几个方面思考:
- TCP 拥塞控制:慢启动、拥塞避免、快速重传和恢复
- 网络拥塞
- 使用 wireshark 查看丢包率
- TCP 的窗口
- MTU(最大传输单元)
- Qos(服务质量)
- 网络设备质量
- 发送和接收缓冲区大小、并发连接数
Server 端命令:
iperf3 -s -i 1
Client 端命令:
iperf3 -c S端IP -i 1 -t 30 -P8
- 影响因素
- 信号强度 rssi
- CCA
- wifi standard
- ac
- ax
- be
- 信道
- 带宽
- tcp/udp
- iperf 命令使用
- iperf3 -c S端IP -i1 -t30 -w2M -P8
- 问题分类
- 屏蔽室 Peek T-Put
- linkspeed
- mcs
- wifi standard
- 路由
- 环境
- mcs
- Tcp
- 调整窗口
- EDCA
- 上行
- data rate
- wlan_radio.data_rate
- retry 数量
- 不同 rate 的 Tx Power
- RTS
- antenna
- radiotap.dbm_antsignal
- data rate
- 下行
- CPU 中断负载
- phy rate
- retry 数量
- rx_mode
- ps mode
- beamforming
- linkspeed
- 拉锯问题
- RSSI
- 外接天线
- 下载速率问题
- 控制变量
- 下载 apk
- 下载引擎
- 对齐网关
- 屏蔽室
- 不差
- EDCA
- RTS
- 差
- DNS Server
- RTT
- 不差
- 控制变量
- 竞速问题
- EDCA
- 热点
- STA
- RTS
- phy rate
- cca
- EDCA
- BTC 问题
- 屏蔽室差
- 分时比例
- 20/40M 带宽
- BT 不同业务是否有差别
- 屏蔽室不差
- EDCA
- RTS
- 屏蔽室差
- SAP 吞吐
- 关闭 IPA 是否有差别?
- wifi standard
- beamformer
- 屏蔽室 Peek T-Put
8. ServerManager 介绍
介绍:在Android系统中,ServiceManager.isDeclared(HAL_INSTANCE_NAME) 用于检查某个AIDL(Android Interface Definition Language)服务是否已经声明并注册到Service Manager中。Service Manager是Android系统中的一个核心组件,负责管理和注册各种系统服务。以下是对ServiceManager.isDeclared方法的具体操作和作用的详细解释:
8.1 Server Manager的作用
- 服务注册:Service Manager 是一个全局的服务注册表,所有系统服务在启动时都会向Service Manager注册自己。
- 服务查找:客户端可以通过Service Manager查找和连接到注册的服务。
- 进程间通信:Service Manager 通过Binder机制支持进程间通信(IPC),使得不同进程中的组件可以互相通信。
8.2 ServiceManager.isDeclared 方法的作用
ServiceManager.isDeclared(HAL_INSTANCE_NAME) 方法用于检查指定的服务实例是否已经注册到Service Manager中。具体来说,它会执行以下操作:
- 参数:HAL_INSTANCE_NAME, 服务的唯一标识,通常是一个字符串,表示要检查的服务实例的名称
- 步骤:连接到Service Manager:
- ServiceManager 会尝试连接到Service Manager进程,通常是通过Binder机制
- 如果Service Manager进程还没有启动,ServiceManager 会等待其启动。
2.查询服务:
- ServiceManager 会向Service Manager发送一个查询请求,请求中包含HAL_INSTANCE_NAME。
- Service Manager会检查其内部的服务注册表,查找是否存在一个与HAL_INSTANCE_NAME匹配的服务实例。
3.返回结果:
- 如果找到了匹配的服务实例,ServiceManager.isDeclared 方法会返回true。
- 如果没有找到匹配的服务实例,ServiceManager.isDeclared 方法会返回false。
9. WifiCond 的介绍
简介:
WifiNl80211Manager.java 和 wificond 是 Android Wifi 框架中的核心底层组件,共同负责与内核驱动交互,实现 WiFi 扫描和管理功能。
-
wificond 的定义与作用
wificond(Wi-Fi Condition Daemon)是一个独立的 Native 进程(位于 system/connectivity/wificond/),作为 Android Wi-Fi 框架与 Linux 内核之间的桥梁。其主要作用包括:- 驱动交互:通过 nl80211 协议(基于 Netlink Socket)直接与 Wi-Fi 驱动通信,执行扫描、获取结果等底层操作
- 扫描管理:上层调用接口到 wificond,wificond 发送扫描命令给驱动:
NL80211_CMD_TRIGGER_SCAN - 事件监听:使用 Looper 监听 Netlink Socket 事件,实现异步相应
-
wificond 的核心功能
- 频段支持:处理 2.4GHz、5GHz(含 DFS 频道)、6GHz 等多频段扫描,并在国家码变更(notifyCountryCodeChanged)后动态调整扫描策略
- 服务暴露:通过 Binder 服务 IWificond.aidl(服务名 wifinl80211)向上层提供接口,供 Java 框架调用
- 进程隔离:作为独立进程运行,避免 Wi-Fi 驱动交互导致的系统稳定性问题(如崩溃不影响系统主进程)
-
WifiNl80211Manager.java 的角色
- 该 Java 类(路径:frameworks/base/wifi/java/android/net/wifi/nl80211/)是 wificond 的 Java 层封装,作用包括:
- Binder 调用代理:通过 IWificond.aidl 接口调用 wificond 的 Native 方法(如扫描、获取结果)
- 结果转换:将 wificond 返回的原始扫描数据(如 SSID、BSSID、信号强度)封装为 Android API 标准格式(如 ScanResult 对象)
- 状态同步:管理扫描请求队列,协调多应用并发扫描需求,优化功耗
-
技术协作流程示例(Wi-Fi 扫描)
- 应用层:WifiManager.startScan() 发起扫描请求
- Framework 层:WifiNl80211Manager 通过 Binder 调用 wificond 的 scan() 方法
- wificond 层:
- 发送 NL80211_CMD_TRIGGER_SCAN 到内核驱动
- 通过 Netlink 监听扫描结果,解析为 AP 列表
- 结果回传:wificond 返回数据 → WifiNl80211Manager 转换为 ScanResult 列表 → 应用通过广播接收结果

总结
wificond:是 Android 专用的 Wi-Fi 驱动交互守护进程,直接操作 nl80211 命令,承担底层扫描、结果解析等核心任务
WifiNl80211Manager:作为 Java 层适配器,封装 wificond 的 Binder 接口,实现数据转换与同步,为上层 WifiManager 提供支持
总的来说:wificond 是一个独立的进程(native进程, 即使崩溃也不会影响到主线程),它支持对 wifi 的管理(比如扫描,信道支持,国家码监听),WifiNL80211Manager 这个类通过 AIDL 接口调用 Wificond,以提供 API 给 Settings 调用。wificond 是可以直接与驱动通信的,通信方式是通过 Netlink Socket 发送消息给内核驱动的。wificond 在初始化的时候,会创建NetLink 套接字。
10. Android Wifi 中的 NetLInk 是什么?
通信协议:
- 基于 Socket API 的特殊协议(AF_NETLINK协议族),类似 TCP/UDP Socket,但专用于内核-用户空间通信
- 在 Android Wifi 中,使用 NETLINK_GENEGIC 子协议(具体为 nl80211)传递 WiFi 控制命令
角色定位:
- 桥梁作用:连接用户态守护进程与内核 WiFi 子系统(cfg80211 框架)
- 替代方案:相比 ioctl, Netlink 支持异步通信、多播、大数据传输,更适合 wifi 管理
作用:
- 命令下发
![image]()
- 事件上报
- 数据传递
为什么 Android wifi 要使用 NetLInk?
- 高性能:直接内存拷贝,无需多次数据复制
- 异步通信:内核可主动推送事件(如扫描结果、断开连接)
- 模块化扩展
- 权限控制:通过 SELinux 策略限制仅系统进程(如 wificond)可访问 Netlink Socke
完整通信流程示例:

11. WCN 介绍(以 wifi 举例)
WCN, Wireless Connectivity,通常指的是一个集成了多种无线通信技术的芯片。
主要功能:
- 支持多种 wifi 标准,如 802.11a/b/g/n/ac/ax 等
- 提供告诉数据传输、低延迟和高可靠性
- 支持多频段操作(2.4GHz 和 5GHz)
- 支持多种安全协议,如 WPA3
WCN架构
-
硬件层:
- RF(射频)前端:负责信号的发送和接收
- 基带处理器:处理基带信号,包括调制解调、信道编码
- 存储器:用于存储固件和数据
- 电源管理
-
固件层:wifi固件:实现wifi协议栈,包括 mac 层和 PHY 层
-
驱动层:Wifi 驱动:与操作系统的网络栈交互、提供接口和控制功能
-
协议栈层:Wifi 协议栈:实现 802.11 标准 ,包括各种管理帧、数据帧和控制帧的处理
PS
-
基带:
Baseband,指在通信系统中,未经调制的原始信号所占用的频率范围。
基带信号通常是指低频或直流信号,其频率范围从0 Hz(直流)到某个相对较低的频率。基带信号可以直接在通信系统中传输,但通常需要进行调制以适应远距离传输或特定信道的要求 -
基带信号:
BaseBand Signal,基带信号是指未经调制的原始信号,通常包含信息的原始形式。例如,在数字通信中,基带信号可以是二进制的0和1序列;在模拟通信中,基带信号可以是语音信号或视频信号。基带信号的频率范围较低,通常在0 Hz到几MHz之间。 -
调制:
Modulation,调制是将基带信号转换为适合传输的高频信号(载波信号)的过程。常见的调制方式包括AM(振幅调制)、FM(频率调制)和 PSK(相移监控)等 -
解调:
Demodulation,解调是将接收到的高频信号(载波信号)转换回基带信号的过程。解调过程通常在接收端的基带处理器中进行 -
基带信号为什么需要调制到高频才能传输信号?
高频信号具有更好的传输特性,可以传输更远的距离;高频段有更多的可用频谱资源,可以避免干扰;高频信号可以利用多径效应提高传输质量;高频信号的天线和电路设计相对简单;符合法规和标准的要求。通过调制技术,基带信号可以有效地转换为高频信号,从而实现高效、可靠、远距离的无线通信 -
固件:
WCN 固件指的是运行在硬件上的软件,负责控制和管理无线通信功能。固件是介于硬件和操作系统之间的关键层,确保各种无线通信技术的正常运行。
在 Android 系统中,固件的代码文件一般保存在vendor/firmware_mnt/image目录下,在使用 wifi 的时候,从指定目录加载文件(其中可能修改了一些配置,成为更新固件)并运行。
12. LNA 和 PA
LNA(低噪声放大器):功能是在接收信号时放大微弱的信号,同时尽量减少噪声的引入。它通常位于接收链路的前端,紧接在天线之后,应用于接收信号
功放(功率放大器):功能是在发射信号时放大信号的功率,使其达到足够高的水平,以便在无线信道中有效传输,应用于发送信号(基站、卫星通信)
LNA和功放在射频系统中的位置
- 接收链路:天线 --> LNA --> 滤波器 --> 混频器 --> 基带处理
- 发送链路:基带处理 --> 上变频 -->滤波器 --> 功放 --> 天线
13. 高通Wifi架构组件介绍

13.1 Daemon
13.1.1 CNSS Daemon
CNSS(Connectivity Network Service Subsystem Daemon),负责管理和协调各种无线连接功能,包括WiFi、蓝牙、NFC等
- 初始化驱动程序
- 配置和管理无线设备参数,如 Mac 地址、信道、传输功率等
- 注册和管理各种无线连接服务,如 wifi 服务,蓝牙服务
- 在系统启动的时候,CNSS Daemon 负责初始化各种无线连接的驱动和设备
- 运行时,接收来自应用层的请求,如连接wifi、扫描蓝牙等
- 在系统关闭时,卸载各种无线连接服务
13.1.2 LOWI Daemon
LOWI Daemon (Location and WiFi Information) 是高通WiFi架构中的一个重要组件,负责收集和处理WiFi相关的数据,支持位置服务和网络优化。通过定期扫描、数据处理、位置估计和网络优化,LOWI Daemon 提供了高精度的室内定位服务和智能的网络管理功能,广泛应用于各种室内导航和位置感知场景
13.1.3 DIAG Daemon
DIAG,Diagnostic Daemon,负责手机和处理各种诊断信息,提供了丰富的接口和工具,用于监控和分析wifi的运行状态和性能数据。
13.1.4 WPA Supplicant
wpa_supplicant 主要负责管理和处理wifi网络的认证和功能,用于 WPA 和 WPA2 认证协议,确保无线网络的安全连接。
四次握手:
- 第一次:AP 向 STA 发送一个 EAPOL(Extensible Authentication Protocol over LAN)帧,包含一个随机生成的 Nonce(ANonce,AP Nonce)
目的是通过 ANonce 向 STA 证明自己是合法的接入点,并开始协商会话密钥 - 第二次:STA 向 AP 发送一个 EAPOL 帧,包含一个随机生成的 Nonce(SNonce,Station Nonce)和一个密钥信息(Key Information)字段;
目的: STA 通过 SNonce 向 AP 证明自己是合法的客户端,并提供必要的密钥信息;
密钥信息: 包含一个 MIC(Message Integrity Code),用于验证消息的完整性和来源 - 第三次:AP 向 STA 发送一个 EAPOL 帧,包含一个安装指示(Install bit)和一个密钥信息字段。
目的: AP 通过设置安装指示,通知 STA 安装会话密钥,并提供最终的密钥信息
密钥信息: 包含一个 MIC,用于验证消息的完整性和来源 - 第四次:STA 向 AP 发送一个 EAPOL 帧,确认会话密钥的安装,并包含一个密钥信息字段
目的:STA 通过设置安装指示,通知 AP 安装会话密钥,并提供最终的密钥信息
密钥信息:包含一个 MIC,用于验证消息的完整性和来源
13.1.5 Hostapd
全称 Host Access Point Daemon,用于管理和配置无线接入点(Access Point, AP)的功能。
- 支持多种AP模式,包括基本的AP模式、热点模式、多AP模式
- 管理AP的网络配置,包括 SSID、信道、传输功率等
- 客户端管理:广利和控制连接到 AP 的客户端设备,包括连接、断开、剔除等操作
- 在系统启动时,hostapd 负责初始化AP功能,加载配置文件和日志记录器
- 注册各种事件处理函数,准备接收和处理无线设备的运行事件
- 在运行时,实时处理无线设备的运行事件,如连接成功、断开连接、信号变化等
一般来说用户使用热点的场景就是从 Settings 界面点击打开热点,然后就不管了,能用就行。热点就是依赖于 hostapd 守护进程来维护的,包括设备的连接、断开、剔除黑名单(ACS, Access Controller List)等操作。
13.1.6 FTM Daemon
全称 Fine Timing Measurement Daemon,用于管理和执行 FTM 操作。FTM是一种测距技术,用于精确测量设备之间的距离。
距离测量的原理:与目标设备交换 FTM 帧,处理 FTM 帧中的时间戳,计算设备之间的精确距离;基于时间戳和多路径处理结果,计算最终的测量结果。
13.2 Linux Network Stack
Linux 网络协议栈是处理网络数据包的核心软件层,负责在硬件驱动(如wifi芯片)与上层应用之间实现数据的分层处理、路由和协议解析。在高通平台中,该协议栈通过与CNSS子系统协同工作,优化无线通信性能。
数据包处理流程(以 wifi 接收为例)

13.3 OS Interface Layer(HDD)
HDD, Host Device Driver. 负责在操作系统和wifi硬件之间提供接口。HDD是高通wifi驱动程序的一部分,主要作用是管理和配置wifi设备,处理数据报的收发,并与操作系统的网络堆栈进行交互。
13.4 UMAC protocol(Client, SAP)
全称 Upper Mac,负责处理高层的 MAC 层功能,对应的有 LMAC(Lower MAC)。有两种模式:Client 和 SAP
UMAC Client 模式
2.1 功能
连接管理:处理客户端与AP(接入点)的连接和断开连接。
认证管理:处理与AP的认证过程,支持多种认证协议,如WPA、WPA2、WPA3、802.1X等。
关联管理:处理与AP的关联和去关联过程,包括扫描、连接请求、关联响应等。
数据传输:处理客户端与AP之间的数据传输,包括数据包的发送和接收。
QoS管理:实现QoS(Quality of Service)功能,确保高优先级数据包的优先传输。
漫游管理:处理客户端的漫游过程,确保在不同AP之间的平滑切换。
2.2 工作原理
扫描:客户端通过扫描周围的AP,获取可用的网络信息,包括SSID、信道、信号强度等。
连接请求:客户端选择一个AP,发送连接请求,请求与AP建立连接。
认证:AP对客户端进行认证,支持多种认证协议,如WPA、WPA2、WPA3、802.1X等。
关联:认证通过后,客户端与AP进行关联,建立数据传输通道。
数据传输:客户端与AP之间进行数据传输,包括数据包的发送和接收。
QoS管理:实现QoS功能,确保高优先级数据包的优先传输。
漫游:当客户端移动到另一个AP的覆盖范围时,进行漫游过程,确保在不同AP之间的平滑切
UMAC SAP 模式
3.1 功能
AP管理:管理AP的功能,包括启动、停止、配置等。
关联管理:处理客户端与AP的关联和去关联过程,包括扫描请求、连接请求、关联响应等。
认证管理:处理与客户端的认证过程,支持多种认证协议,如WPA、WPA2、WPA3、802.1X等。
数据传输:处理AP与客户端之间的数据传输,包括数据包的发送和接收。
QoS管理:实现QoS功能,确保高优先级数据包的优先传输。
安全性和认证:实现多种安全特性和认证协议,确保AP连接的安全性。
3.2 工作原理
启动AP:启动AP,配置AP的参数,如SSID、信道、传输功率等。
扫描请求:处理客户端的扫描请求,提供可用的网络信息。
连接请求:处理客户端的连接请求,请求与客户端建立连接。
认证:对客户端进行认证,支持多种认证协议,如WPA、WPA2、WPA3、802.1X等。
关联:认证通过后,与客户端进行关联,建立数据传输通道。
数据传输:AP与客户端之间进行数据传输,包括数据包的发送和接收。
QoS管理:实现QoS功能,确保高优先级数据包的优先传输。
安全性和认证:实现多种安全特性和认证协议,确保AP连接的安全性。
13.5 WMI
WMI(WiFi Management Interface)是一个关键组件,负责在主机和目标之间提供管理和控制接口。通过交换命令和事件,WMI实现对WiFi设备的配置、管理和监控
WMI通过UMAC(Upper MAC)接口与UMAC协议层交互,处理高层的MAC层功能,如关联管理、认证管理、数据传输等
13.6 HTC
HTC(Host Target Communication)是一个重要的组件,负责在主机(Host)和目标(Target)之间提供高效、可靠的通信接口。
HTC通过在主机和目标之间交换数据包和控制消息,实现对WiFi设备的配置、管理和监控
13.7 HIF(Bus Driver)
在高通WiFi架构中,HIF(Host Interface)或称为BUS Driver是一个关键组件,负责在主机和目标之间提供硬件级别的通信接口。通过特定的物理传输层(如PCIe、SDIO、USB等),HIF实现数据包和控制消息的高效传输。HIF具有高效性、可靠性、灵活性和低延迟等优势
PCIE 接口:类似内存条的插槽
SDIO 接口:类似 SD 存储卡的接触点
USB 接口:常见
13.8 CDP Interface
CDP(Common Data Path)Interface是一个重要的组件,负责在不同的网络协议层之间提供统一的数据路径接口。CDP Interface旨在简化数据包的处理流程,提高数据传输的效率和可靠性
-
Config:配置,wifi设备的各种参数,如 SSID、信道、传输功率
通常使用配置文件,如 hostapd.conf, wpa_supplicant.conf 指定设备和协议的配置参数
动态配置:通过控制接口,如 wpa_cli, hostapd_cli 动态修改设备和协议的配置参数 -
Monitor Mode/PKTLOG
监控模式,可以捕获所有经过的无线数据包,包括管理帧、控制帧和数据帧,应用于抓 sniffer 生成 pcap 文件 -
Tx Core
处理数据包的发送流程,包括数据包的封装、校验和计算、发送到网络设备
将数据包传递到上层协议(如IP层、TCP/UDP层)进行处理。
通过HIF(Host Interface)或BUS Driver将数据包发送到网络设备 -
Rx Core
处理数据包的接收流程,包括数据包的解封装、校验和验证、传递到上层协议
去除不必要的头部(如MAC头部、IP头部),解封装数据包。
将数据包传递到上层协议(如IP层、TCP/UDP层)进行处理。 -
HTT
Host Target Transport, 提供主机和目标之间的高效数据传输接口
通过HTT接口传输数据包,支持多种传输层协议(如PCIe、SDIO、USB) -
HAL(HW Abstractrion Layer)
硬件抽象层, 提供一个统一的接口,使上层软件可以独立于具体的硬件平台进行开发
在系统启动时,初始化硬件资源,配置硬件参数
在高通WiFi架构中,Config、Monitor Mode/PKTLOG、Tx Core、Rx Core、HTT和HAL(硬件抽象层)是多个协同工作的组件和接口,共同实现高效、可靠和灵活的WiFi通信。每个组件和接口都有其特定的功能和工作原理,通过相互协作,确保了WiFi设备的高性能和高可靠
13.9 QDF (OSAbstraction)
QDF(Qualcomm Development Framework)是一个重要的组件,主要负责操作系统抽象(OS Abstraction)。QDF的作用是提供一个统一的接口,使WiFi驱动和协议栈可以独立于具体的操作系统进行开发和运行。这样可以提高代码的可移植性和可维护性,同时简化开发工作。
13.10 PlatformDriver/ BoostSW
PlatformDriver(平台驱动)和BoostSW(性能优化软件)是两个重要的组件,分别负责硬件平台的驱动管理和性能优化
14. MAC 帧介绍
14.1 MAC 帧格式
802.11 MAC帧格式如下图所示:

MAC 帧由以下三个基本域组成:
- MAC Header:包括帧控制(Frame Control)、时长(Duration)、地址(Address)等。注意,每个方框上面的数字表示该域占据的字节数。例如 Frame Control 需要 2 字节
- Frame Body:代表数据域。这部分内容的长度可变,其具体存储的内容由帧类型(type)和子类型(sub type)决定。
- FCS:(Frame Check Sequence, 帧校验序列)用于保障帧数据完整性
14.2 Frame Control 域
Frame Control 域共 2 字节 16 位,具体字段划分如下图所示:

- Protocol Version:代表 802.11 MAC 帧的版本号。目前的值为 0.
- Type 和 SubType:这两个字段用于指明 MAC 帧的类型。802.11 中 MAC 帧可划分为三种类型,分别是 control、data和management,每种类型和帧用于完成不同功能
- To DS 和 From DS:只用在数据类型的帧中
- More Fragments:表明数据是否分片。只支持 data 和 management 帧类型
- Retry:如果该值为 1,表明是重传包
- Power Management:表明发送该帧的 STA 处于活跃模式还是处于省电模式
- More Data:和省电模式有关。AP 会为那些处于省电模式下的 STA 缓存一些数据帧,而 STA 会定时查询是否有数据要接收。该参数表示 AP 中还有缓存的数据帧。如果该值为 0,表明 STA已经接收完了
- Protected Frame:表明数据是否加密
- Order:指明接收端必须按顺序处理该帧
Type 和 SubType 的含义如下表所示,只列出了部分的取值

From DS 和 To DS 的取值

14.3 Duration/ID 域
Duration/ID 域占 2 字节共 16 位,其具体含义根据 Type 和 SubType 的不同而变化,不过大体就两种,分别代表 ID 和 Duration。
- 对于 PS-POLL 帧,该域表示 AID 的值。其中最后 2 位必须为 1,而前 14 位取值为 1~2007。这就是该域取名 ID 之意
- 对于其他帧,代表离下一帧到来还有多长时间,单位是微秒,us。这就是该域取名 Duration 之意。
14.4 Address 域
先介绍 MAC 地址的特点:
- MAC 地址可用 6 字节的十六进制来表示,如:
2c:fe:4f:30:23:cf - MAC 地址的组成包括两个部分。0~23 位,即前面一半是厂商向 IETF 等机构申请用来标识厂商的代码,也称为“组织唯一标识符”(Organizaitonally Unique Identifier, OUI)。后 24 位是各个厂商制造的所有网卡的唯一编号
- 第 48 位用于表示这个地址是组播地址还是单播地址。如果这一位是 0,表示此 MAC 地址是单播地址;如果这位是 1,表示此 MAC 地址是组播地址。例如01-XX-XX-XX-XX-XX为组播地址。另外,如果地址全为1,例如FF-FF-FF-FF-FF-FF,则为MAC广播地址。
- 第47位表示该MAC地址是全球唯一的还是本地唯一。故该位也称为G/L位
这里的第 47 和 48 位,应该是从右往左数
MAC 地址示意图如下:

这里应该是从左往右开始数,为什么描述相反不知道,反正本质描述的是一个事情
- 字节序为Big-endian,即最高字节在前。所以图中的first byte实际对应的MAC地址最左边一组。以Note 2 MAC地址90-18-7C-69-88-E2为例,first byte就是“90”(如果是Little-endian,则first byte是"E2"),其OUI是SamsungE,代表三星电子
- 比特序为Little-endian,即最低位在前。这就是01-XX-XX-XX-XX-XX为组播地址的原因了。因为“01”对应的二进制是“0000-0001”,其第0位是1,应该放在图中first byte最左边一格
802.11 MAC 帧头部共包含 4 个 Address 域,但是规范中却有五中地址定义:
- BSSID:在基础型 BSS 中,它是 AP 的地址。而在 IBSS 中则是一个本地唯一 MAC 地址。该地址由一个 46 位的随机数生成,并且 U/M 位为 0, G/L 位为 1.另外对 MAC 广播来说,其名称为 wildcard BSSID。BSS 是一种基本的服务集,通常由一个AP(Access Point)和多个STA(Station)组成;IBSS 也称为Ad-hoc网络,是一种没有AP的网络,所有STA都是对等的。STA 之间可以直接通信,不需要通过中心节点。
- 目标地址(Destination Address, DA):用来描述 MAC 数据包最终接收者(final recipient),可以是单播或组播地址。
- 源地址(Source Address, SA):用来描述最初发出 MAC 数据的 STA 地址。一般情况下都是单播地址
- 发送 STA 地址(Transmitter Address, TA):用于描述将 MAC 数据包发送到 WM 中的 STA 地址
- 接收 STA 地址(Receiver Address, RA):用于描述接收 MAC 帧数据的。如果某个 MAC 帧数据接收者也是 STA,那么 RA 和 DA 一样。但如果接收者不是无线工作站,而是比如以太网中的某台 PC,那么 DA 就是该机器的 MAC 地址,而 RA 则是 AP 的 MAC 地址。这就表明该帧将先发给 AP,然后由 AP 转发给 PC。
上述无线地址中,一般只使用Address 1~Address 3三个字段,故图3-13中它们的位置排在一起。表3-4展示了Address域的用法

Address1 用作接收端,Address2 用作发送端。Address3 携带其他信息用于帮助 MAC 帧的传输,针对不同类型,各个 Address 的用法如下:
- IBSS 网络中,由于不存在 DS,所以 Address1 指明接收者,Address2 代表发送者。Address3 被设置为 BSSID,其作用是:如果 Address1 被设置为组播地址,那么只有位于同一个 BSSID 的 STA 才有必要接收数据。
- 基础结构型网络中,如果 STA 发送数据,Address1 必须是 BSSID,代表 AP。因为这种网络中,所有数据都必须通过 AP。Address3 代表最终的接收者,一般是 DS 上的某个目标地址
- 基础结构型网络中,如果数据从AP来,那么Address 1指明STA的地址,Address 2代表AP的地址,Address 3则代表DS上的某个源端地址。
- Address 4只在无线网络桥接的时候才使用
下图为基础型结构网络和无线桥接情况下不同地址的使用场景:

如图3-16所示:
- 数据包发往DS的情况下,SA和TA一致,而RA和BSSID一致。
- 数据包来自DS的情况下,RA和DA一致,而TA和BSSID一致。
- 无线桥接的情况下,SA、TA、RA和DA四种地址都派上了用场。
14.5 Sequence Control 域
Sequence Control 域长 16 位,前 4 位代表片段编号(Fragment Number),后 12 位是帧顺序编号(Sequence Number),如下图:

- Sequence Number:STA 每次发送数据帧时都会设置一个帧顺序编号。注意,控制帧没有帧顺序编号。另外,重传帧不使用新的帧顺序编号
- Fragment Number:用于控制分片帧。如果数据量太大,则 MAC 层会将其分片发送。每个分片帧都有对应的分片编号。
14.6 总结
一图以蔽之

15. 控制帧
控制帧的作用包括协助数据帧的传递、管理无线媒介的访问等。规范中定义的控制帧有好几种,这里介绍四种,他们的帧格式如下图(控制帧不包含数据,故长度都不大):

- RTS(Request To Send):RTS 用于申请无线媒介(信道)的使用时间。值为 Duration,单位是微秒。Duration 的计算大致是:要发送的数据帧或管理帧所需时间 + CTS 帧所需时间 + ACK 所需时间 + 3 SIFS 时间
- CTS(Clear To Send):也和CSMA/CA有关,用于回复RTS帧。另外它被802.11g保护机制用来避免干扰旧的STA。
- ACK:802.11中,MAC以及任何数据的传输都需要得到肯定确认。这些数据包括普通的数据传输、RTS/CTS交换之前帧以及分片帧。
- PS-POLL:该控制帧被STA用于从AP中获取因省电模式而缓存的数据。其中AID的值是STA和AP关联时,由AP赋给该STA的。
16. 管理帧
管理帧是 802.11 中非常重要的一部分。重要的几种管理帧:Beacon、Association Request/Response、Probe Request/Response、Authentication/Deauthentication
管理帧格式:

所有的管理帧都包括 MAC Header 的 6 个域。不过,无线网络要管理的内容如此之多,这6个域肯定不能承担如此重任,所以管理帧中的Frame Body将携带具体的管理信息数据。
802.11的管理信息数据大体可分为两种类型:
- 定长字段:指长度固定的信息,规范称为Fixed Field
- 信息元素:指长度不固定的信息。显然这类信息中一定会有一个参数用于指示最终的数据长度
从程序员的角度来看,不同的管理信息数据就好像不同的数据类型或数据结构一样。下面我们来看看802.11为管理帧定义了哪些数据类型和数据结构。
16.1 定长字段
管理帧中固定长度的字段如下:
-
Authentication Algorithm Number:该字段占2字节,代表认证过程中所使用的认证类型。其取值如下
- 0:代表开放系统身份认证(Open System Authentication)
- 1:代表共享密钥身份认证(Shared Key Authentication)
- 2:代表快速BSS切换(Fast BSS Transition)
- 3:代表SAE(Simultaneous Authentication of Equals)。用于两个STA互相认证的方法,常用于Mesh BSS网络
- 65535:代表厂商自定义算法
-
Beacon Interval field:该字段占2字节。每隔一段时间AP就会发出Beacon信号用来宣布无线网络的存在。该信号包含了BSS参数等重要信息。所以STA必须要监听Beacon信号。Beacon Interval field字段用来表示Beacon信号之间间隔的时间,其单位为Time Units(规范中缩写为TU。注意,一个TU为1024微秒。这里采用2作为基数进行计算)。一般该字段会设置为100个TU
-
Capability Information(性能信息):该字段长2字节,一般通过Beacon帧、Probe Request和Response帧携带它。该字段用于宣告此网络具备何种功能。2字节中的每一位(共16位)都用来表示网络是否拥有某项功能。该字段的格式如下图:
![image]()
- ESS/IBSS:基础结构型网络中,AP将设置ESS位为1,IBSS位为0。相反,IBSS中,STA设置ESS位为0,而IBSS位为1。Mesh BSS中,这两个位都为0
- Privacy:如果传输过程中需要维护数据机密性(data confidentiality),则AP设置该位为1,否则为0。
- Spectrum Mgmt:如果某设备对应MIB中dot11SpectrumManagementRequired为真,则该位为1。根据802.11 MIB对dot11SpectrumManagementRequired的描述,它和前面介绍的TPC(传输功率控制)和DFS(动态频率选择)功能有关
- Radio Measurement:如果某设备对应MIB中的dot11RadioMeasurementActivated值为真,则该位置为1,用于表示无线网络支持Radio Measurement Service。
-
Current AP Address:该字段长6字节,表示当前和STA关联的AP的MAC地址。其作用是便于关联和重新关联操作
-
Listen Interval:该值长2字节,和省电模式有关。其作用是告知AP,STA进入PS模式后,每隔多长时间它会醒来接收Beacon帧。AP可以根据该值为STA设置对应的缓存大小,该值越长,对应的缓冲也相应较大。该值的单位是前文提到的另外一个定长字段Beacon Interval。
-
Association ID(AID):该字段长2字节。STA和AP关联后,AP会为其分配一个AssociationID用于后续的管理和控制(如PS-POLL帧的使用)。不过为了和帧头中的Duration/ID匹配,其最高2位永远为1,取值范围1~2007。
-
Reason Code:该字段长2字节。用于通知Diassociaton、Deauthentication等操作(包括DELTS、DELBA、DLS Teardown等)失败的原因。
![image]()
-
Status Code:该字段长2字节,用于反馈某次操作的处理结果。0代表成功
16.2 信息元素
信息元素(IE)包含数据长度不固定的信息,其标准结构如图3-22所示。其中,Element ID表示不同的信息元素类型。Length表示Information字段的长度。根据Element ID的不同,Information中包含不同的信息

表3-6列出了几种Element ID及Length的取值情况

16.3 常用管理帧
16.3.1 Beacon 帧
Beacon 非常重要,AP定时发送Beacon帧用来声明某个网络。这样,STA通过Beacon帧就知道该网络还存在。此外,Beacon帧还携带了网络的一些信息。简单来说,Beacon帧就是某个网络的心跳信息。Beacon帧能携带的信息非常多,不过并非所有信息都会包含在Beacon帧中

16.3.2 Probe Request/Response
STA除了监听Beacon帧以了解网络信息外,还可以发送ProbeRequest帧用于搜索周围的无线网络。规范要求由送出Beacon帧的STA回复Probe Response帧,这样,在基础结构型网络中,Beacon帧只能由AP发送,故Probe Response也由AP发送。IBSS中,STA轮流发送Beacon帧,故Probe Response由最后一次发送Beacon帧的STA发送

当AP收到Probe Request时,会响应以Probe Response帧。Probe Response帧包含的内容绝大部分和Beacon帧一样
16.3.3 Association Request/Response
当STA需要关联到某个AP时,将发送此帧

针对Association Request帧,AP会回复一个Association Response帧用于通知关联请求处理结果

16.3.4 Authentication
用于身份验证

17. 数据帧
数据帧格式如下:

18. sniffer 中过滤各种帧的条件
| 帧类型 | 过滤器语法 |
|---|---|
| Management frame | wlan.fc.type == 0 |
| Control frame | wlan.fc.type == 1 |
| Data frame | wlan.fc.type == 2 |
| Association requset | wlan.fc.type_subtype == 0x00 |
| Association response | wlan.fc.type_subtype == 0x01 |
| Reassociation request | wlan.fc.type_subtype == 0x02 |
| Reassociation response | wlan.fc.type_subtype == 0x03 |
| Porbe request | wlan.fc.type_subtype == 0x04 |
| Probe response | wlan.fc.type_subtype == 0x05 |
| Beacon | wlan.fc.type_subtype == 0x08 |
| Disassociate | wlan.fc.type_subtype == 0x0A |
| Authentication | wlan.fc.type_subtype == 0x0B |
| Deauthentication | wlan.fc.type_subtype == 0x0C |
| Action frame | wlan.fc.type_subtype == 0x0D |
| Block Ack requests | wlan.fc.type_subtype == 0x18 |
| Block Ack | wlan.fc.type_subtype == 0x19 |
| Power save poll | wlan.fc.type_subtype == 0x1A |
| Request to send | wlan.fc.type_subtype == 0x1B |
| Clear to send | wlan.fc.type_subtype == 0x1C |
| ACK | wlan.fc.type_subtype == 0x1D |
| Contention free period end | wlan.fc.type_subtype == 0x1E |
| NULL data | wlan.fc.type_subtype == 0x24 |
| QoS data | wlan.fc.type_subtype == 0x28 |
| Null QoS data | wlan.fc.type_subtype == 0x2C |
| Transimitter address | wlan.ta == [mac addr] |
| Source address | wlan.sa |
| Destination address | wlan.da |
| BSSID | wlan.bssid |
18. Wifi HAL 是什么,充当了什么作用?
简述:
- Wi-Fi HAL是连接上层 Wi-Fi 管理服务和底层硬件驱动程序的中间层,提供标准化的接口
标准化接口:
- 通过 AIDL 或 HIDL 定义,提供一致的方法和数据结构
硬件控制:
- 提供对 Wi-Fi 硬件的低级控制和高级功能支持
数据传输:
- 在上层应用和服务与底层硬件驱动程序之间传输数据
状态管理:
- 报告硬件状态和发送事件通知
Android Wifi 中有三个 HAL 接口:
- Vendor 供应商 HAL(处理硬件相关,包括厂商定制化)
- 客户端 HAL(wpa_supplicant 交互,管理 Wi-Fi 客户端连接,包括连接管理、安全配置和扫描功能)
- Hostapd HAL(与Hostapd交互,管理热点相关)
Wi-Fi HAL 的使用:
- 初始化和连接:初始化 wifi hal,获取 wifi 芯片和接口对象
- 配置 wifi 芯片:设置 wifi 芯片的工作模式
- 管理 wifi 接口:创建和配置 wifi 接口
- 扫描和连接:执行网络扫描,连接到特定的 wifi 网络
- 管理连接状态:获取和管理当前的连接状态
- 管理 AP 模式:启用 AP 模式,配置 AP 参数,管理连接到 AP 的客户端
- 事件处理:注册事件回调,处理特定事件
19. Android是怎么监控内存泄漏的,原理是什么?
19.1 开源监测工具:LeakCanary
LeakCanary 的原理很简单:在 Activity 或 Fragment 被销毁后,将他们的引用包装成一个 WeakReference,然后将这个 WeakReference 关联到一个 ReferenceQueue。查看 ReferenceQueue 中是否含有 Activity 或 Fragment 的引用。如果没有,触发 GC 后再次查看。还是没有,那么就说明回收成功,否则就可能发生了内存泄漏。这时候开始 dump 内存的信息,并分析泄露的引用链。
接入方法:
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
}
在 Application.onCreate 方法中显式调用 LeakCanary.install(this); 开启 LeakCanary 的内存监控。
19.2 内存泄漏的常见场景
总结
内存泄露问题的修复方案可能会有很多种,而且也会有快速修复方法,但希望各位能把泄露的root cause找到,简单的修复方案可能只是将问题掩盖了,检测工具检测不出来,但没有实质性解决泄露问题~
希望各位在写代码的时候,能在脑海中模拟出手机运行这段代码的场景,从开始到消亡,做好控制~一段好的代码,高质量的代码,就跟艺术品一样,需要各位花些心思,这样才能真正解决手机的内存问题或其他问题,一点一点让手机更流畅~
附常见的修复方案:
1:使用Application的Context,替换Activity的context
2:使用弱引用,GC会来决定引用的对象何时回收并将对象从内存中移除(注意使用时要判空)
3:手动置空,解除引用关系
4:代码控制异步线程的生命周期,及时cancel
5:将内部类设置为static,因为非静态内部类会隐式持有外部类实例的引用
6:注册和取消注册成对出现,在对象合适的生命周期进行监听的注销
7:资源性对象(比如Cursor、File等)往往都做了一些缓冲,在不使用时应该及时关闭
1、AsyncTask 使用异常,最为常见
关键引用
GC ROOT thread java.lang.Thread.<Java Local> (named 'AsyncTask #17')
原理:
在使用 AsyncTask 时,一般会继承 AsyncTask 并重写 doInBackground 方法,onPostExecute 方法,在 doInBackground 方法中做耗时操作,在 onPostExecute 方法中更新 UI,这是日常用法
泄露场景:
当 Activity 调用 onDestroy 方法后,AsyncTask 的方法没有执行完成,或者是在 doInBackground 方法中,或者是在 onPostExecute 方法中,而 AysncTask 持有 Activity 的引用(一般是非静态内部类持有外部类的引用和匿名内存类持有外部类的引用两种形式)导致 Activity 无法及时回收,从而导致内存泄漏
解决方法
- cancel + isCancelled ,强烈推荐
- 将 AsyncTask 作为静态内部类存在(与 Handler 处理方式相似),避免内部类的 this$0 持有外部类的引用
- 如果 AysncTask 中需要使用 Context,建议使用 WeakReference
- 如果确实需要做相对耗时的操作,建议用 Service 去做而不是 AsyncTask,推荐
2、Handler,Runnable(Thread)泄露问题
关键引用
references android.os.MessageQueue.mMessages'
references android.os.Message.callback'
原理:
作为 Android 的一个通信利器,消息机制永远都是不可忽略的,主要是靠 Handler,Message, MessageQueue,Looper 四个类来完成各自任务
Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息
MessageQueue:消息队列的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next)
Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应的消息事件(Handler.handleMessage)
Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者
泄露场景:
当我们使用 Handler 时,往往会在 Activity 创建非静态 Handler 实例,重写 handleMessage 方法,此时会隐式持有外部 Activity 引用,而 MessageQueue 持有 Message 引用,Message 持有 Handler 引用,也就是说 Message 不被消费,就不会释放 Activity;很多业务组会 postDlayed,在几分钟后打点或者统计操作,都是不合理的。或者在 Message 中处理非常耗时的操作,最后造成消息堆积,无法得到及时处理,最后造成内存泄漏。
Runnable(Thread)泄露相对更容易理解,主要是异步线程持有外部 Activity 的引用,而回调 Activity onDistroy 方法时,线程没有执行完成,导致内存泄露
解决方法
- 在 Activity 的 onDestroy 执行时,Handler 泄露可手动调用 Handler 的 removeCallbacksAndMessages,清除异步消息,Runnable(Thread)泄露则可通过终止线程,切断引用链 -- 推荐
- 将 Handler, Runnable(Thread) 定义为静态内部类,推荐。==》通过此方式,不会隐式持有外部 Activity 的引用
- 如果确实需要使用 Activity 做相关操作,建议使用弱引用,或者使用 ApplicationContext,推荐
- 如果确实有耗时操作,剪辑使用 jobschedule 去做,推荐
3、HandlerThread 泄露
关键引用
GC ROOT android.os.HandlerThread.<Java Local>
原理
HandlerThread 的封装其实也是为了解决线程通信,本质还是线程,只不过内部建立了 Looper,从上面的 Handler 了解到如果一个线程处理消息,需要 Handler,Message,MessageQueue,Looper四者完成各自任务,一般使用的时候会手动调用 Looper.prepare(),Looper.loop() 方法(主线程除外,主线程会创建 Looper 对象并开启消息循环),而使用 HandlerThread 时,相对简单一些,一般创建 HandlerThread 并开启,就可以进行线程通信了
解决方法
- 在 Activity 中的 onDestroy 方法中,手动调用 HandlerThread 的 quit 方法,强烈推荐。
当我们调用 HandlerThread 的 quit 方法时,实际就是执行了 MessageQueue 中的 removeAllMessagesLocked 方法,把 MessageQueue 消息池中的所有消息全部清空,无论是延时消息(延迟消息是指通过 sendMessageDelayed 或通过 postDelayed 等方法发送的需要延迟执行的消息)还是非延迟消息。
在 HandlerThread 中还有一个方法:quitSafely,实际执行的是 removeAllFutureMessageLocked 方法,只会清空 MessageQueue 消息池中所有的延迟消息,并将所有非延迟消息派发出去让 Handler 处理,相比于 quit 更安全一些。这个看业务组需求,一般 Activity 都退出了,消息派不派发都没有实际意义了。
- 将 HandlerThread 定义为静态内部类,推荐
- 使用 ApplicationContext,推荐
4、非静态内部类持有外部类的引用
说明:这是个很笼统的概念,引起此种泄露的原因可能很多,希望能找到真正泄露的东西,而不是简单的将其改成 static 或者使用 ApplicationContext
关键引用
this$0
原理
泄露出现的场景,主要是非静态内部类隐式持有外部 Activity 的引用,而非静态内部类的生命周期超出了 Activity 的生命周期,在 Activity 执行 onDestroy 方法时,由于非静态内部类隐式持有外部 Activity 的引用,导致 Activity 无法 GC,从而导致内存泄漏
this$0 是什么:this$0 的意思就是所说的隐式持有外部Activity引用,内部类可以访问外部类的成员变量,靠的就是 this$0 ,这个东西是编译器自动加上的,不需要手动定义,在反编译的 smali 文件中很容易看到(如果有很多层内部类的嵌套,会有 this$1, this$2)
解决方法
- 非静态内部类持有外部类的应用,主要是非静态内部类的生命周期超过了 Activity 的生命周期,但原因可能有很多种,或者是 AsyncTask 问题,或者是 Runnable 问题,或者是未 unregister 问题,或者是资源未关闭问题; 建议找到泄露的真凶,从引用链着手,如果没有思路可以看看 hprof 做进一步的分析,墙裂推荐
- 如果想快速修复,可以有几个办法:如非静态内部类改为静态内部类,如使用 ApplicationContext,但都不是很推荐(用就完了!)
5、匿名内部类持有外部类引用
说明:跟 4 很类似,也是个很笼统的概念,引起此种泄露的原因可能有很多,希望能找到真正泄露的东西,而不是简单的将其改成static或者使用ApplicationContext
关键引用
this$0;anonymous
原理
泄露出现的场景主要是匿名内部类隐式持有外部 Activity 的引用,而匿名内部类的生命周期超出了 Activity 的生命周期,在Activity执行onDestroy方法时,由于匿名内部类隐式持有外部Activity的引用,导致Activity无法GC,从而导致内存泄露.与(4)基本是一个道理,与(4)的差别,在反编译的时候经常会看到xxxxx$1.class,xxxxxx$2.class,这些就是匿名内部类,经常的书写格式一般是new xxxxxx() { 类的成员变量,成员方法 }.xxxxx();
解决办法
不要贪图用匿名内部类的代码简洁而忽略了内存泄露问题,对于有泄露风险的匿名内部类,建议都要改成内部类的形式~强烈推荐,然后再找到真正泄露的点,这就回到(4)的解决方案
6、static变量持有 activity
此种泄露相对简单好解一些,从引用链上基本就可以判断问题出在什么地方。
关键引用
GC ROOT static 加上应用的包名
原理
static 成员变量的使用不恰当,在某个时机,将 activity 传入当做 context,从而导致 Activity 无法正常被回收
解决方法
- 找到 static 成员变量泄露的 Activity 的时机,并将其引用链剪断即可
- 如果可以,将 static 变量恢复为非 static 变量,使其可以正常 GC
- 如果确实需要 context,且需要保持 static ,则可使用 ApplicationContext
7、static View
此种问题比较好确认,GC ROOT 是包名相关的 View 名称
关键引用
GC ROOT static 包名**[View名称]
原理
当某个 View 初始化时耗费大量资源,而且要求 Activity 生命周期内保持不变,这个时候很多业务组可能会把 View 变成 static,加载到视图树上(View Hierachy),像这样,当 Activity 被销毁时,应当释放资源。但很可能会带来泄露问题,View 是跟 Context 紧密关联的,使用不当就会出现泄露问题,需要特别注意。
可能有的朋友说,我在使用 View 的时候没操作 Context,怎么会有 Activity 的引用呢?
其实 View 的代码中默认有 Context
public View(Context context) {
mContext = context;
}
Context 是什么时候给到 View 的呢?View 创建的时候,new View,有的时候使我们写代码时自己 new,更多的时候是 setContentView 时将 Activity作为Context传给 View
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
解决办法
- 通过设计改变 static 为普通变量,不要在 Android 中使用 static 修饰 view,完全避免此种可能,推荐
- 在 onDestroy 时,将 static view 置为 NULL;
8、资源未关闭
对于使用了 BraodcastReceiver,ContentObserver,File, Cursor,Stream,Bitmap 等资源的代码,应该在 Activity 销毁时及时关闭或注销,否则这些资源将不会被回收,造成内存泄漏
9、注册的监听器未注销
在Android程序里面存在很多需要 register 和 unregister 的监听器,我们需要确保及时 unregister 监听器
20. 怎么分析ANR
https://www.cnblogs.com/huansky/p/13944132.html
20.1 ANR 概述
ANR 全称 Application NO Response,是 Android 系统用来检测应用主线程(UI线程)超时故障,用来判断应用是否存在卡死或者卡顿响应慢的问题。如果应用位于前台,会通过弹窗操作,提供给用户杀死应用和等待的原则。

20.2 ANR 类型 -- 4类
- Input ANR -- InputDispatchingTimedOut
应用程序主线程在 5 秒内没有完成用户的 Input 事件,logcat 日志关键字:Input event dispatching timed out - Service ANR --- ServiceTimeout
- 应用程序没有执行完成 service 的 bind/create/start/destroy/unbind 操作
- 前台服务 20 秒超时,后台服务 200 秒超时
- logcat 关键字
Timeout executing service
- Broadcast ANR --- BroadcastTimeout
- 应用程序在规定时间内没有执行完成 onReceive 操作
- 前台广播 10 秒超时,后台广播 60 秒超时
- logcat 关键字:
Timeout of broadcast BroadcastRecord
- ContentProvider ANR --- ContentProviderTimeout
- 应用程序在 10 秒内没有执行完成 ContentProvider 相关操作
- logcat 日志关键字:
timeout publishing content providers
20.3 ANR 常见原因
-
主线程耗时操作,如复杂的 layout,庞大的 for 循环,一般存在单条消息耗时或者多条消息整体耗时
-
主线程消息队列存在大量的消息,一般是有消息泄露,大量消息需要执行出现整体耗时,导致对应组件消息执行 delay
-
主线程前面的消息执行耗时,导致后面的消息 delay
-
主线程被子线程同步锁 block,可能为子线程耗时操作或者发生死锁
-
主线程设置了同步屏障并且没有移除,导致后续消息无法处理
-
startForceground 未在 Service 的 onStartCommand 中执行; 广播应用可以指定处理 onReceiver 的线程,对应线程阻塞也会导致广播 ANR
-
主线程被 Binder 对端 block,主线程在对另一个进程进行通过 binder 调用,而后者处理调用阻塞耗时或者Binder线程池无法处理该 Binder 请求。
-
主线程 i/o 耗时
-
得不到系统资源,这种情况一般像内存泄漏,高度压力测试或者高温限制系统资源等情况
20.4 通用分析步骤
根据以上 ANR 常见的原因,第 1-6 类原因导致的 ANR 一般都是应用自身的问题,需要应用 Owner 自己优化处理,而后面三类原因可能需要定位阻塞的对端进程或者服务是谁提供,流转到对应团队分析。
首先在接触到 ANR 问题时,我们先检查一下日志是否完整,通常抓的 284 日志比较完整,包括 bugreport 和 /data/anr目录的日志
-
确定 ANR 发生的类型和第一时间点
我们通常知道从 System log 中搜索 “ANR In” 这一关键字出现的 log,从而确定 ANR 的类型和时间,但是这个 log 出现的时间点已经不是第一现场,因为在这之前会打印英勇的调用站信息,可能会 delay 几秒甚至十几秒,所以需要搜索 event log 中 am_anr 出现的 log 以确定 ANR 时间点,进程 pid 以及什么类型 ANR,等待了多久,也可以根据不同类型的 ANR 查找更早的日志确认发生的第一时间
![image]()
-
查看 ANR 进程 trace 信息
发生 ANR 的应用调用栈信息会在 /data/anr 目录下以时间来命名,如 /data/anr/anr_2021-06-22-15-37-37-623
![image]()
-
查看 CPU 信息
在 System log 的 “ANR in”log中,会打印 CPU 在问题发生前后一个时间段的 CPU 统计情况,以便确定是否和 CPU 资源占用,IO wait等有关,CPU 占有率因为统计时间的滞后的问题有时候不是完全跟 ANR 现场 match 上,所以这个信息只能作为一点参考,大多数情况并不是那么精准,所以借鉴这个信息的前提还是基于主线程消息处理的分析。CPU的统计方法是一段时间内不同进程或线程在用户态和内核态分配的CPU时间片/统计总时间,如果当前8核都在,则占满是 800%,同理如果2个被拔核,剩余6个核工作,占满则是 600%。
![image]()
-
检查是否和进程冻结相关
连续启动应用时,容易造成 CPU 资源的抢夺,导致应用启动变慢,所以性能同事引入进程冻结功能。
在启动应用时冻结后台其他进程,将 CPU 资源集中让给前台应用,从而提高启动应用的时间
![image]()
21. 怎么分析 wifi 上网慢
- 连接 wifi 的速度 mWifiInfo 链路传输速率
- DHCP 过程是否花费时间长(DhcpClient) DNS Probe 延迟
- TCPdump 时间点是否大量重传
- 确认 tx/rx 情况 cca_busy 情况
- 看是否报了 datastall 事件
- host_driver 日志 和 FW 日志
22. Android 系统的开机流程
Android 系统启动过程是一个复杂但是有序的过程,涉及多个阶段和组件。从开机到用户界面的显示,每个阶段都有特定的任务和责任。以下是详细步骤

- 引导加载程序(Bootloader)
- 加载内核和初始化 RAM
- 当设备开机时,首先运行的是引导加载程序(Bootloader)
- Bootloader 负责加载内核(Kernel)和初始 RAM 磁盘(init RAM Disk)到内存中
- 内核启动后,会挂在初始 RAM 磁盘作为根文件系统
- 加载内核和初始化 RAM
- 内核初始化
- 硬件初始化
- 内核启动后,会初始化硬件设备,如 CPU、内存、存储设备、网络设备
- 内核会加载必要的驱动程序,以便与硬件进行通信
- 启动第一个用户空间进程
- 内核启动完成后,会启动第一个用户空间进程
init,这是 Android 系统的初始化进程
- 内核启动完成后,会启动第一个用户空间进程
- 硬件初始化
- init 进程
- 解析 init.rc 文件
- init 进程会解析 init.rc 文件,该文件定义了系统启动时需要执行的命令和创建的进程
- init.rc 文件还定义了系统启动时的各个阶段(如 early-init, init, late-init)
- 启动系统服务
- init 进程会启动一些关键的系统服务,如 zygote, surfaceflinger, servicemanager 等
- servicemanager 负责管理Android系统的服务,surfaceflinger 负责管理图形显示
- 解析 init.rc 文件
- zygote 进程
- 启动 zygote
- zygote 是 Android 系统中的一个重要进程,负责启动和管理所有 java 应用程序的进程
- zygote 会加载 Dalvik 虚拟机,并预加载一些常用的类和资源
- 启动 syste_server
- zygote 会启动 system_server 进程,该进程是 Android 系统的核心服务容器
- system_server 负责启动和管理各种系统服务,如 ActivityManagerService、WindowManagerService、PackageManagerService等
- 启动 zygote
- 系统服务启动
- 启动关键系统服务
- system_server:进程会启动多个关键的系统服务,这些服务负责管理应用程序的生命周期、用户界面、存储、网格等
- ActivityManagerService:负责管理应用程序的活动(Activity)
- WindowManagerService:负责管理窗口和用户界面
- PackageManagerService:负责管理已安装的应用程序
- 启动关键系统服务
- 启动 Launcher 应用
- 启动 Launcher
- 当 system_server 完成启动后,ActivityManagerService 会启动 Launcher 应用,这是用户看到的第一个界面。
- Launcher 应用负责主屏幕和桌面图标
- 启动 Launcher
- 用户界面显示
- 显示主屏幕
- Launcher 应用启动后,用户界面会显示主屏幕,用户可以开始与设备进行交互
- 显示主屏幕
- 后续启动过程
- 启动其他应用程序
- 用户可以通过 Launcher 启动其他应用程序
- 每个应用程序都会由 zygote 进程派生出一个新的进程来运行
- 启动其他应用程序
总结
Android 系统启动过程可以分为以下几个主要阶段:
1.引导加载程序(Bootloader):加载内核和初始 RAM 磁盘。
2.内核初始化:初始化硬件设备并启动 init 进程。
3.init 进程:解析 init.rc 文件并启动关键系统服务。
4.zygote 进程:启动 system_server 进程。
5.系统服务启动:启动各种系统服务。
6.启动 Launcher 应用:显示用户界面。
7.用户界面显示:用户可以开始与设备进行交互。
23. Android中应用程序的启动流程
总结
Android 应用程序的启动流程可以分为以下几个主要阶段:
1.用户启动应用程序:用户通过主屏幕点击应用图标。
2.Launcher 应用发送启动请求:Launcher 发送 Intent。
3.ActivityManagerService 处理启动请求:解析 Intent,检查权限,创建应用进程。
4.应用进程启动:加载应用的 Application 类,调用 onCreate 方法。
5.启动主 Activity:创建并初始化目标 Activity,调用生命周期方法。
6.绘制用户界面:加载布局文件,绘制界面。
7.用户界面显示:显示用户界面,用户可以开始与应用进行交互。
8.应用程序运行:处理用户输入,管理 Activity 生命周期。
- 用户启动应用程序
- 用户操作:用户通过主屏幕(Launcher)点击应用程序图标,发起启动请求
- Launcher 应用发送启动请求
- 发送 Intent
- Launcher 应用会发送一个 Intent,该 Intent 包含了要启动的 Activity 的信息(如包名、类名等)
- Intent 通过 ActivityManagerService(AMS) 进行处理
- 发送 Intent
- ActivityManagerService 处理启动请求
- 解析 Intent
- ActivityManagerService 收到 Intent 后,会解析 Intent 以确定要启动的 Activity
- ActivityManagerService 会查询 PackageManagerService 获取应用程序的组件信息
- 检查权限
- ActivityManagerService 会检查启动该 Activity 所需的权限,确保应用有权限启动
- 创建应用进程
- 如果目标应用还没有运行,ActivityManagerService 会通过 Zygote 进程创建一个新的应用进程
- Zygote 进程会 fork 一个新进程,并在新进程中加载应用的代码和资源。
- 解析 Intent
- 应用进程启动
- 加载应用
- 新创建的进程会加载英勇的 Application 类,并调用 Application 的 onCreate 方法
- 应用的 Application 类是应用的全局入口点,可以在这里进行全局初始化
- 加载应用
- 启动主 Activity
- 创建 Activity
- ActivityManagerService 会通知新创建的进程启动指定的 Activity
- 应用进程中的 ActivityThread 会创建并初始化目标 Activity
- 调用生命周期方法:
- ActivityThread 会一次调用 Activity 的生命周期方法
- onCreate:创建 Activity,初始化界面和数据
- onStart:Activity 变为可见,但尚未与用户交互
- onResume:Activity 变为前台,可以与用户交互
- ActivityThread 会一次调用 Activity 的生命周期方法
- 创建 Activity
- 绘制用户界面
- 加载布局
- 在 onCreate 方法中,通常会调用 setContentView 方法加载布局文件
- 布局文件被解析并生成相应的 View 对象树
- 绘制界面
- ActivityThread 会将 View 对象树传递给 WindowManagerService,有 WindowManagerService 负责绘制界面
- SurfaceFlinger 负责将绘制的内容显示在屏幕上
- 加载布局
- 用户界面显示
- 显示界面
- 当所有绘制操作完成后,用户界面会显示在屏幕上,用户可以开始与应用进行交互
- 显示界面
- 应用程序运行
- 处理用户输入
- 应用程序会监听用户输入事件(如触摸、按键等),并相应地处理这些事件
- 当用户操作导致 Activity 状态变化时,会调用相应的生命周期方法(如 onPause, onStop, onDestroy)
- 处理用户输入
24. Handler 机制
总结
Handler 机制通过 Looper 和 MessageQueue 实现了线程间的消息传递和任务调度。主要组件包括:
Handler:发送和处理消息。
Looper:管理消息队列,运行消息循环。
MessageQueue:存储消息的队列。
Message:消息对象,用于传递数据。
Handler 机制是 Android 中用于在不同线程之间传递消息和执行任务的重要机制。它通过 Looper 和 MessageQueue 实现了线程间的消息传递和任务调度。
- 主要组件
- 1.1 Handler
- 作用:Handler 是最常用的最贱,用于发送和处理消息
- 方法:
- sendMessage(Message mg):发送一条消息到 MessageQueue
- post(Runnable r):将一个 Runnable 对象添加到 MessageQueue,稍后再 Lopper 的 loop 方法中执行
- handleMessage(Message msg):处理从 MessageQueue 中取出的消息
- 1.2 Looper
- 作用:每个线程可以有一个 Looper,用于管理该线程的 MessageQueue
- 方法:
- prepare():为当前线程准备一个 Looper
- loop():开始一个消息循环,不断从 MessageQueue 中取出消息并分发给相应的 Handler
- quit():结束消息循环
- 1.3 MessageQueue
- 作用:消息队列,用于存储 Handler 发送的消息
- 方法:
- enqueueMessage(Message msg, long when):将消息添加到队列中
- next():从队列中取出下一个消息
- 1.4 Message
- 作用:消息对象,用于在 Handler 之间传递数据
- 字段:
- what:消息类型标识
- arg1 和 arg2:简单的整数参数
- obj:任意对象,用于传递复杂的数据
- 1.1 Handler
- 工作流程
- 2.1 Looper 创建
- 主线程:在 Android 应用的主线程(UI 线程)中,Looper 会在 ActivityThread 的 main 方法中自动创建
public static void main(String[] args) { SamplingProfilerIntegration.start(); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } - 子线程:在子线程中,需要手动调用 Looper.prepare() 和 Looper.loop() 来创建和启动 Looper
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // 处理消息 } }; Looper.loop(); } }).start();
- 主线程:在 Android 应用的主线程(UI 线程)中,Looper 会在 ActivityThread 的 main 方法中自动创建
- 2.2 Handler 创建
- 创建 Handler:在有 Looper 的线程中创建Handler
Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // 处理消息 } };
- 创建 Handler:在有 Looper 的线程中创建Handler
- 2.3 发送消息
- 发送消息:使用 Handler 的 sendMessage 方法发送消息
Message msg = Message.obtain(); msg.what = 1; msg.obj = "Hello, Handler!"; handler.sendMessage(msg); - 发送 Runnable:使用 Handler 的 post 方法发送 Runnable
handler.post(new Runnable() { @Override public void run() { // 执行任务 } });
- 发送消息:使用 Handler 的 sendMessage 方法发送消息
- 2.4 消息处理
- 消息循环:Looper 的 loop 方法不断从 MessageQueue 中取出消息,并分发给相应的 Handler
public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // 取出消息 if (msg == null) { return; } try { msg.target.dispatchMessage(msg); // 分发消息 } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } } } - 处理消息:Handler 的 handlerMessage 方法被调用,处理消息
@Override public void handleMessage(Message msg) { switch (msg.what) { case 1: String data = (String) msg.obj; Log.d("Handler", data); break; default: break; } }
- 消息循环:Looper 的 loop 方法不断从 MessageQueue 中取出消息,并分发给相应的 Handler
- 2.1 Looper 创建
- 示例代码
- 3.1 主线程的 Handler
public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: String data = (String) msg.obj; Log.d("MainActivity", data); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { Message msg = Message.obtain(); msg.what = 1; msg.obj = "Hello from background thread!"; mHandler.sendMessage(msg); } }).start(); } }); } } - 3.2 子线程中的 Handler
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: String data = (String) msg.obj; Log.d("BackgroundThread", data); break; default: break; } } }; Message msg = Message.obtain(); msg.what = 1; msg.obj = "Hello from background thread!"; handler.sendMessage(msg); Looper.loop(); } }).start();
- 3.1 主线程的 Handler
25. Handler 机制中 MessageQueue 为空时,会发生什么?
总结
当 MessageQueue 为空时,Looper 的 loop 方法会进入等待状态,直到有新的消息被添加到 MessageQueue 中
当 MessageQueue 为空时,Looper 的 loop 方法会进入等待状态,不会消耗 CPU 资源。一旦有新的消息被添加到 MessageQueue 中,Looper 会立即处理这些消息。这种机制确保了消息的高效处理和线程的低功耗。
- Looper 的 loop 方法
Looper 的 loop 方法是一个无线循环,它不断从 MessageQueue 中取出消息并分发给相应的 Handler。public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // 取出消息 if (msg == null) { return; // 如果消息队列为空,返回 } try { msg.target.dispatchMessage(msg); // 分发消息 } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } } } - MessageQueue 的 next 方法
MessageQueue 的 next 方法负责从队列中取出下一个消息。如果队列为空,next 方法会进入等待状态,直到有新的消息被添加到队列中。以下是 next 方法的核心逻辑:Message next() { // 1. 检查是否需要退出消息循环 final long ptr = mPtr; if (ptr == 0) { return null; } // 2. 从本地队列中取出消息 Message msg; if (mPendingNotNull) { msg = mPending; mPending = null; mPendingNotNull = false; } else { // 3. 调用 native 方法从队列中取出消息 final long timeout = (mPolling ? 0 : -1); msg = nativePollOnce(ptr, timeout); } // 4. 处理取出的消息 if (msg != null) { if (msg.target == null) { // 如果消息的目标为 null,表示这是一个同步屏障 synchronized (this) { mMessages = msg.next; } msg.recycle(); continue; } if (msg.workSourceUid != UID_NONE) { // 设置工作源 UID msg.workSourceUid = WorkSource.UID_NONE; } } return msg; } - MessageQueue 为空的行为
- 等待状态:当 MessageQueue 为空时,next 方法会调用 nativePollOnce 方法,该方法会进入等待状态。nativePollOnce 是一个 native 方法,它会阻塞当前线程,直到有新的消息被添加到 MessageQueue 中
- 唤醒机制:当有新的消息被添加到 MessageQueue 中时,MessageQueue 会唤醒阻塞的 nativePollOnce 方法,使其返回新的消息
- 实际效果
- 线程阻塞:当 MessageQueue 为空时,looper 的 loop 方法会阻塞在 nativePollOnce 方法上,不会消耗 CPU 资源
- 相应新消息:一旦有新的消息被添加到 MessageQueue 中,nativePollOnce 方法会返回,loop 方法会继续执行,取出并处理新的消息
- 代码示例:
在这个示例中,当用户点击按钮时,会启动一个子线程模拟长时间操作。在操作完成之前,MessageQueue 为空,Looper 的 loop 方法会阻塞。当子线程发送消息时,MessageQueue 会被唤醒,Looper 会处理新的消息。public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: String data = (String) msg.obj; Log.d("MainActivity", data); break; default: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { // 模拟长时间操作 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Message msg = Message.obtain(); msg.what = 1; msg.obj = "Hello from background thread!"; mHandler.sendMessage(msg); } }).start(); } }); } }
26. Handler 机制中怎么将消息插入到最前面执行?
总结
MessageQueue 使用了 单链表 的方式对消息进行存储,所以便于 插入 和 删除 操作
使用 sendMessageAtFrontOfQueue 方法可以将消息插入到 MessageQueue 的最前面,确保它优先执行。这在需要处理紧急任务或重要消息时非常有用。通过合理使用这个方法,可以更好地控制消息的处理顺序,提高应用的响应性和性能。
- sendMessageAtFrontOfQueue 方法
public final boolean sendMessageAtFrountOfQueue(Message msg) - 注意事项:
- 优先级:虽然 sendMessageAtFrontOfQueue 方法将消息插入到队列的最前面,但它仍然会遵循 Looper 的消息处理机制。如果 Looper 当前正在处理其他消息,有限消息会在当前消息处理完毕后立即处理
- 线程安全:sendMessageAtFrontOfQueue 方法是线程安全的,可以在任何线程中调用
- 其他相关方法:
- sendMessageAtTime:允许你指定消息的执行时间
- sendMessageDelayed:允许你执行消息的延迟时间
26. Handler 的同步屏障
一点点个人理解:同步屏障相当于在消息队列中横向插入一张过滤网,异步的消息可以通过,同步的消息不能通过,所以可以实现发送异步消息来进行指定顺序执行代码逻辑
同步屏障(Synchronization Barrier)是 Android 系统中 Handler 机制的一种同步工具,用于确保在某些特定条件下,消息队列中的某些消息能够按照特定的顺序执行。同步屏障通常用于多线程环境下的同步问题,确保某些关键的操作能够顺序执行,避免数据竞争和不一致的问题。
在 Handler 机制中,同步屏障的实现主要依赖于 MessageQueue 类。当设置一个同步屏障时,MessageQueue会阻止所有优先级低于屏障的消息被去除和执行,直到屏障被移除。这样可以确保屏障前后的消息按预期顺序执行。
以下是一些关于同步屏障的关键点:
-
设置同步屏障
int barrierToken = mQueue.postSyncBarrier();
这行代码会在消息队列中插入一个同步屏障,并返回一个屏障标记(barrierToken),用于后续移除屏障 -
移除同步屏障
mQueue.removeSyncBarrier(barrierToken);
使用之前返回的barrierToken来移除同步屏障,使得屏障之后的消息可以被处理 -
应用场景
- UI 更新:在多线程环境下,确保 UI 更新操作按照预期顺序执行,避免界面显示不一致
- 数据同步:在多个线程中进行数据操作时,确保某些关键操作按顺序完成,避免数据竞争
-
注意事项
- 同步屏障会阻塞所有优先级低于屏障的消息,因此使用时需要注意性能影响,避免长时间阻塞消息队列
- 同步屏障适用于需要严格顺序执行的场景,但在大多数情况下,通过合理的设计和使用其他同步机制(如 Lock, Semaphore等)可以避免过度使用同步屏障

27. AMS 和 PMS
总结
AMS:负责管理应用程序组件的生命周期,确保应用程序的正常运行和用户体验。
PMS:负责管理应用程序包的安装、卸载和查询,确保应用程序的完整性和安全性。
交互:AMS 和 PMS 之间有紧密的交互,共同确保应用程序的正常运行和管理。
AMS:Activity Manager Service
PMS:Package Manager Service
-
Activity Manager Service (AMS)
AMS 是 Android 系统中负责管理应用程序组件(如 Activity、Service、BroadcastReceiver 和 ContentProvider)生命周期的核心服务,主要职责包括:- 管理 Activity 的生命周期:控制 Activity 的启动、暂停、恢复和销毁等操作
- 管理 Service 的生命周期:控制 Service 的启动、绑定、解绑、和销毁等操作
- 管理 BroadcastReceiver 的注册和接收:负责广播的发送和接收
- 管理 ContentProvider 的注册和访问:控制 ContentProvider 的创建和销毁
- 任务管理:管理应用程序的任务栈,确保用户在多个应用程序之间切换时的体验
- 资源管理:管理应用程序的资源分配和释放,确保系统资源的高效利用
- 权限管理:检查应用程序的权限,确保应用程序在执行敏感操作时具有必要的权限
-
Package Manager Service (PMS)
PMS 是 Android 系统中负责管理应用程序包(APK 文件)的安装、卸载、查询等操作的核心服务。主要职责包括:- 安装应用程序:处理应用程序的安装请求,解析 APK 文件、验证签名,并将应用程序安装到系统中
- 卸载应用程序:处理应用程序的卸载请求,删除应用程序的数据和文件
- 查询应用程序信息:提供 API 供其他组件查询已安装应用程序的信息,如包名、版本号、图标、权限等
- 管理应用程序数据:管理应用程序的数据目录,确保应用程序的数据存储和访问
- 权限管理:管理和验证应用程序的权限,确保应用程序在安装和运行时具有必要的权限
- 资源管理:管理应用程序的资源文件,如布局文件、图片、字符串等
- 签名验证:验证应用程序的签名,确保应用程序的完整性和安全性
-
AMS 和 PMS 的交互
AMS 和 PMS 之间有紧密的交互,共同确保应用程序的正常运行和管理。以下是一些常见的交互场景:- 应用程序启动:当用户启动一个应用程序时,AMS 会调用 PMS 来查询应用程序的包信息和权限,确保应用程序可以正常启动
- 权限检查:在应用程序执行敏感操作时,AMS 会调用 PMS 来检查应用程序是否具有必要的权限
- 安装和卸载:当用户安装或卸载应用程序时,PMS 会通知 AMS 更新应用程序的状态,确保系统中的应用程序的列表和状态一致
- 资源管理:AMS 和 PMS 会共同管理应用程序的资源,确保应用程序再启动和运行时能够访问所需的资源
-
代码示例
使用 AMS 启动 ActivityIntent intent = new Intent(this, TargetActivity.class); startActivity(intent);使用 PMS 查询已安装应用程序的信息
PackageManager packageManager = getPackageManager(); List<PackageInfo> packages = packageManager.getInstalledPackages(0); for (PackageInfo packageInfo : packages) { Log.d("PackageManager", "Package: " + packageInfo.packageName); Log.d("PackageManager", "Version: " + packageInfo.versionName); }
28. Android 架构模型
Android 系统架构分为五层:从上到下依次是 应用层、应用架构层、系统运行库层、硬件抽象层、Linux 内核层

1、应用层:
- 包含用户可以直接使用的各种应用程序,如电话、短信、浏览器等
- 开发者可以使用 Android SDK 提供的 API 来开发自己的应用程序
2、应用架构层:
- 提供了一些列的高级 API,供开发者使用,如 Activity、Service、BroadcastReceiver、ContentProvider 等
- 这一层还包括各种系统服务,如通知管理、资源管理、位置管理等
3、系统运行库层:
- 包含了各种 C/C++ 库,提供了底层系统的功能支持,如图形渲染、媒体播放、数据存储等
- 也包含了 Android 运行时(ART),负责管理应用程序的执行和优化
4、 硬件抽象层:
- 是位于操作系统内核与硬件电路之间的接口层,目的在于将硬件抽象化
- 为了保护硬件厂商的知识产权,它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植
5、Linux 内核层:
- Android 操作系统基于 Linux 内核,提供了设备驱动、内存管理、进程管理、网络栈等核心功能
- 通过内核,Android 可以与硬件进行交互,实现各种底层操作
29. 常见的设计模式
1、单例模式(Singleton Pattern)
- 用途:确保一个类只有一个实例,并提供一个全局访问点
- 应用:例如,用户管理全局配置、数据库连接等
- 示例
public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
2、工厂模式(Factory Pattern)
- 用途:提供一个接口用于创建对象,但让子类决定实例化哪一个类
- 应用:用于创建不同类型的对象,如不同类型的视图、消息等;运营商需求
- 示例
public interface Button { void render(); } public class AndroidButton implements Button { @Override public void render() { System.out.println("Rendering Android button"); } } public class ButtonFactory { public static Button createButton(String type) { if ("android".equals(type)) { return new AndroidButton(); } // 其他类型的按钮 return null; } }
3、观察者模式(Observer Pattern)
- 用途:定义对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新
- 应用:用于实现事件驱动,如按钮点击事件、数据变化监听等
- 实例:
public interface Observer { void update(String message); } public class ConcreteObserver implements Observer { @Override public void update(String message) { System.out.println("Received: " + message); } } public class Subject { private List<Observer> observers = new ArrayList<>(); public void attach(Observer observer) { observers.add(observer); } public void detach(Observer observer) { observers.remove(observer); } public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } }
4、MVC 模式(Model-View-Controller Pattern)
- 用途:将应用程序分为 模型(Model)、视图(View)、控制器(Controller)三个部分,提高代码的可维护性和可扩展性
- 应用:用于构建复杂的用户界面和数据处理逻辑
- 示例:
- Model:处理数据逻辑
- View:展示数据
- Controller:处理用户输入,协调 Model 和 View
- 举例:Model 相当于抽象代码逻辑,可调用的API, View 页面展示数据, Controller 是 Activity,处理点击事件;比如从页面中点击登录按钮,那么 Activity 中处理点击事件、View 中控件获取/设置 账号密码、调用 Model 的代码逻辑验证账户密码正确性。
5、适配器模式(Adapter Pattern):
- 用途:将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作
- 应用:用于处理不同数据源的适配,如适配不同类型的列表项
- 示例:
public interface Target { void request(); } public class Adaptee { public void specificRequest() { System.out.println("Specific request"); } } public class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void request() { adaptee.specificRequest(); } }
30. Java 方法中,局部变量引用的生命周期
问题:java中,在一个方法体内定义了 A a = new A(); 请问 a 引用什么时候被释放?
在 Java 中,对象的生命周期由垃圾回收期(Garbage Collector, GC)管理。当一个对象不再被任何引用所指向时,他就变成了垃圾回收器的回收目标。具体来说,a 引用的生命周期和它所指向的对象的生命周期是两个不同的概念。
- 引用的生命周期
引用 a 的生命周期取决于它的作用于。在 Java 中,局部变量的作用域是它所在的代码块(通常是方法体)。因此,当方法执行完毕时,引用 a 的作用于结束,引用 a 的本身会被销毁。public void myMethod() { A a = new A(); // 在这里,a 是有效的引用 } // 方法执行完毕后,引用 a 的作用域结束 - 对象的生命周期
对象的生命周期取决于它是否被任何活动的引用所指向。即使引用 a 的作用于结束,它所指向的对象 A 仍然可能被其他引用所指向,因此不会立即被垃圾回收器回收。
示例1:引用 a 是唯一的引用
如果引用 a 是对象 A 的唯一引用,那么当方法执行完毕时,对象 A 也将没有被任何引用指向,从而成为 GC 的回收目标
示例2:对象 A 还有其他引用public void myMethod() { A a = new A(); // 在这里,a 是有效的引用 } // 方法执行完毕后,引用 a 的作用域结束,对象 A 也失去了所有引用,可以被垃圾回收
如果对象 A 还有其他引用指向它,那么即使引用 a 的作用于结束,对象 A 也不会被垃圾回收器回收public void myMethod() { A a = new A(); A b = a; // b 也指向了同一个对象 A } // 方法执行完毕后,引用 a 的作用域结束,但对象 A 仍然被引用 b 所指向,不会被垃圾回收
总结
- 引用 a 的生命周期:当方法执行完毕时,引用 a 的作用于结束,引用 a 本身会被销毁
- 对象 A 的生命周期:当对象 A 没有被任何引用指向时,它将成为垃圾回收器的回收目标。具体何时被回收取决于垃圾回收器的运行时机。
因此,a 引用的生命周期在方法执行完毕时结束,而它所指向的对象 A 的生命周期取决于它是否还有其他引用指向它。
31. DNS 解析过程
DNS(Domain Name System, 域名系统)解析过程是将人类可读的域名(如www.example.com)转换为计算机可读的IP地址(如93.184.216.34)的过程。这个过程设计多个步骤和多个 DNS 服务器。以下是 DNS 解析的详细过程:
-
客户端发起请求
当用户在浏览器中输入一个网址(例如www.baidu.com)时,客户端(如浏览器或操作系统)会发起一个 DNS 查询,以获取域名对应的 IP 地址 -
本地 DNS 缓存
客户端首先检查本地 DNS 缓存,如果缓存中有该域名的 IP 地址记录,客户端会直接使用缓存中的 IP 地址,而不会进行后续的 DNS 查询。 -
递归解析器(Recursive Resolver)
如果本地缓存中没有该域名的记录,客户端会向配置的递归解析器(通常是 ISP 提供的 DNS 服务器)发送 DNS 查询请求。递归解析器负责为客户端获取域名的 IP 地址 -
根 DNS 服务器(Root DNS Server)
递归解析器首先向根 DNS 服务器查询。根DNS服务器不直接提供 IP 地址,而是返回负责该顶级域名(如.com)的权威DNS服务器的地址 -
顶级域名服务器(Top-Level Domain Server)
递归解析器相反会的顶级域名服务器查询。顶级域名服务器负责特定顶级域名(如.com .org .net)的解析,它会返回负责该二级域名(如example.com)的权威 DNS 服务器的地址 -
权威 DNS 服务器(Authoritative DNS Server)
递归解析器向返回的权威 DNS 服务器查询。权威 DNS 服务器负责特定域名的解析,他会返回该域名的IP地址 -
返回结果
权威DNS服务器将域名的IP地址返回给递归解析器。递归解析器再将IP地址返回给客户端。 -
缓存结果
客户端收到 IP 地址后,会将其缓存一段时间(根据 DNS 记录中的 TTL 值),以便后续请求时直接使用缓存中的 IP 地址,减少 DNS 查询的次数和时间。
详细流程图:
客户端
--> 本地 DNS 缓存
--> 递归解析器
--> 根 DNS 服务器
--> 顶级域名服务器
--> 权威 DNS 服务器
--> 递归解析器
--> 客户端
示例:
假设用户在浏览器中输入 www.example.com,以下是解析过程的详细步骤:
1.客户端检查本地DNS缓存:
- 如果缓存中有 www.example.com 的IP地址,直接使用。
- 如果没有,继续下一步。
2.客户端向递归解析器发送查询请求:
- 客户端发送 www.example.com 的查询请求给递归解析器。
3.递归解析器向根DNS服务器查询:
- 递归解析器发送查询请求给根DNS服务器。
- 根DNS服务器返回负责 .com 顶级域名的顶级域名服务器的地址。
4.递归解析器向顶级域名服务器查询:
- 递归解析器发送查询请求给 .com 顶级域名服务器。
- 顶级域名服务器返回负责 example.com 的权威DNS服务器的地址。
5.递归解析器向权威DNS服务器查询:
- 递归解析器发送查询请求给 example.com 的权威DNS服务器。
- 权威DNS服务器返回 www.example.com 的IP地址。
6.递归解析器返回结果给客户端:
- 递归解析器将 www.example.com 的IP地址返回给客户端。
7.客户端缓存结果:
- 客户端将 www.example.com 的IP地址缓存一段时间。
- 通过这一系列步骤,客户端最终获取了 www.example.com 的IP地址,可以使用该IP地址进行网络通信。
32. HTTPDNS
HTTPDNS(HTTP Domain Name System)是一种通过HTTP协议进行域名解析的技术,旨在解决传统DNS解析中的一些问题,如DNS劫持、解析延迟和准确性问题。HTTPDNS通过将域名解析请求发送到HTTP服务器,而不是传统的DNS服务器,来获取IP地址。以下是对HTTPDNS的详细介绍:
-
传统DNS解析的问题
DNS劫持:在某些地区,ISP(互联网服务提供商)可能会劫持DNS请求,将用户重定向到恶意网站或广告页面。
解析延迟:传统DNS解析过程中,多次查询不同级别的DNS服务器可能导致解析延迟,影响用户体验。
解析准确性:传统DNS服务器可能会返回不准确的IP地址,导致用户访问不到正确的服务。 -
HTTPDNS的工作原理
HTTPDNS通过以下步骤进行域名解析:1.客户端发起HTTP请求: 客户端(如手机应用或浏览器)通过HTTP协议向HTTPDNS服务器发送域名解析请求。 2.HTTPDNS服务器处理请求: HTTPDNS服务器接收到请求后,根据内部的映射表或其他逻辑,返回域名对应的IP地址。 3.客户端接收响应: 客户端接收到HTTPDNS服务器返回的IP地址,使用该IP地址进行网络通信。 -
HTTPDNS的优势
减少DNS劫持:HTTPDNS请求通常通过HTTPS协议进行,加密传输可以防止中间人攻击和DNS劫持。
降低解析延迟:HTTPDNS服务器可以缓存解析结果,减少多次查询的延迟。
提高解析准确性:HTTPDNS服务器可以根据地理位置、网络状况等信息,返回最优的IP地址,提高解析的准确性。
支持更复杂的逻辑:HTTPDNS服务器可以实现更复杂的解析逻辑,如负载均衡、灰度发布等。 -
HTTPDNS的实现
HTTPDNS可以通过以下几种方式实现:自建HTTPDNS服务器:
企业可以根据自身需求,自建HTTPDNS服务器,管理和维护域名解析。
使用第三方HTTPDNS服务:
多家云服务提供商(如阿里云、腾讯云、华为云等)提供了HTTPDNS服务,企业可以直接使用这些服务,减少自建和维护的成本。 -
HTTPDNS的使用场景
移动应用:移动应用可以通过HTTPDNS提高用户的访问速度和安全性,特别是在网络环境复杂的地区。
游戏:游戏应用可以使用HTTPDNS进行全球负载均衡,确保玩家访问到最近的游戏服务器。
电子商务:电商网站可以使用HTTPDNS优化用户的购物体验,减少页面加载时间。 -
示例
假设一个移动应用使用HTTPDNS进行域名解析,以下是解析过程的详细步骤:1.客户端发起HTTP请求: 客户端通过HTTP协议向HTTPDNS服务器发送域名解析请求,例如 GET /resolve?domain=www.example.com。 2.HTTPDNS服务器处理请求: HTTPDNS服务器接收到请求后,查询内部的映射表,返回 www.example.com 对应的IP地址,例如 93.184.216.34。 3.客户端接收响应: 客户端接收到IP地址 93.184.216.34,使用该IP地址进行网络通信,访问 www.example.com。 -
安全性和隐私
加密传输:HTTPDNS请求通常使用HTTPS协议,确保数据传输的安全性。
隐私保护:HTTPDNS服务提供商需要确保用户数据的隐私保护,不滥用用户信息。
通过使用HTTPDNS,可以有效解决传统DNS解析中的问题,提高用户的访问速度和安全性。
33. Binder 调用
总结
Binder 机制在 Android 系统中提供了高效、安全、灵活的进程间通信方式。
通过内核模块的优化,Binder机制实现了高效的通信,数据在进程间传递时只进行了一次内存拷贝。
单次传输的数据量限制为 4MB,如果需要传输更大的数据,可以通过分快传输、文件描述符等方式进行处理。
通过权限控制和数据加密,可以确保通信的安全性。
Android 中的 Binder 机制是实现进程间通信(Inter-Process Communication,IPC)的核心技术之一。Binder 机制不仅支持高效的进程间通信,还提供了安全性和灵活性。下面是对 Binder 机制的详细解释,包括其基本概念、工作原理、实现细节和使用方法。
33.1 基本概念
33.1.1 Binder
- Binder:Binder是Android系统中用于进程间通信的一个核心概念。它是一个虚拟的实体,用于表示进程间的通信端点
- IBinder:IBinder 是 Binder 接口的基类,定义了基本的 Binder 操作方法,如
queryLocalInterface、transact等 - Binder对象:在服务端创建的 Binder 对象,用于处理客户端的请求
- Binder 代理:在客户端创建 Binder 代理对象,用于与服务端的Binder对象进行通信
33.1.2 AIDL
- AIDL(Android Interface Definition Language):AIDL是Android提供的一种接口定义语言,用于定义进程间通信的接口。通过 AIDL 文件可以生成 Binder 相关的 Java 代码,方便开发者使用。
33.2 工作原理
33.2.1 Binder 驱动程序
- 内核模块:Binder 驱动程序是内核模块,负责管理和调度 Binder 对象。它提供了用户空间进程与内核空间通信的通道
- 通信通道:Binder 驱动程序通过文件描述符(File Descriptor)与用户空间进程通信,管理 Binder 对象的创建、销毁和通信
33.2.2 Binder 实体
- Binder 对象:每个进程可以创建一个或多个Binder对象,这些对象用于表示进程间的通信端点
- Binder 引用:进程间通信时,发送方通过 Binder 引用(IBinder 接口)与接收方的Binder对象进行通信
33.2.3 Binder 代理
- 客户端代理:在客户端进程中,Binder 代理对象(BinderProxy)负责与服务端的Binder对象进行通信
- 服务端代理:在服务端进程中,Binder对象(Binder)接收来自客户端的请求并进行处理
33.2.4 Binder 事务
- 事务类型:Binder 事务包括单向事务(one-way)、同步事务(Synchronous)等
- 事务处理:Binder 驱动程序服务组调度和处理事务,确保事务的正确性和顺序
33.3 实现细节
33.3.1 定义 AIDL 接口
首先定义一个 AIDL 接口文件ICalc.aidl,描述服务端提供的方法
// ICalc.aidl
package com.example.binderdemo;
interface ICalc {
int add(int a, int b);
}
33.3.2 实现服务器
在服务端实现 ICalc 接口,并注册为一个服务
// CalcService.java
package com.example.binderdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class CalcService extends Service {
private final ICalc.Stub binder = new ICalc.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
33.3.3 客户端调用
在客户端通过绑定服务,获取 ICalc 接口并调用其方法:
// MainActivity.java
package com.example.binderdemo;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private ICalc iCalc;
private TextView resultTextView;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// Binder调用
iCalc = ICalc.Stub.asInterface(service);
try {
int result = iCalc.add(10, 20);
resultTextView.setText("Result: " + result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
iCalc = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultTextView = findViewById(R.id.resultTextView);
Button bindButton = findViewById(R.id.bindButton);
bindButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.binderdemo", "com.example.binderdemo.CalcService"));
// 绑定服务
bindService(intent, connection, BIND_AUTO_CREATE);
});
}
}
33.4 内存拷贝和数据量限制
33.4.1 为什么只有一次内存拷贝?
在 Binder 机制中,数据在进程间传递时只进行一次内存拷贝(内存映射),具体过程如下:
- 客户端发起请求:
- 客户端进程将数据写入一个缓冲区,并通过 Binder 驱动程序将请求发送给内核
- 内核处理请求:
- 内核中的 Binder 驱动程序将数据从客户端的缓冲区复制到内核的缓冲区
- 服务端接收数据:
- 服务端进程从内核的缓冲区中读取数据,完成数据的接收。
- 内存映射:
- 创建共享内存区域:当客户端发起通信时,内核空间会创建一块内存区域,并通过 mmap 将其同时映射到客户端的用户空间和内核空间的 Binder 驱动中
- 一次拷贝完成传输:客户端只需要将数据从自己的用户空间拷贝到这块共享内存(属于内核映射给他的区域),由于该内存同事被内核的Binder驱动可见,驱动可以直接读取数据并传递给服务端,无需再进行二次拷贝。
33.4.2 数据量大小限制
- 单次传输的数据量限制:
- 在Android 4.4(API 级别19)及之前,单次传输的数据量限制是 1 MB
- 在Android 5.0(API 界别21)及之后,单次传输的数据量限制增加到 4MB
- 限制数据量的目的是避免过大的数据传输影响系统性能和稳定性
- Binder 事务缓冲区大小:
- 每个Binder对象有一个固定的事务缓冲区大小,默认为 1MB。如果传输的数据超过这个限制,Binder 驱动程序会返回
TransactionTooLargeException异常。
- 每个Binder对象有一个固定的事务缓冲区大小,默认为 1MB。如果传输的数据超过这个限制,Binder 驱动程序会返回
33.5 处理大数据传输
如果需要传输的数据量超过 Binder 的限制,可以采取以下几种方法:
- 分块传输
- 将大数据分割成多个小块,每次传输一个小块,直到所有数据传输完毕
- 使用文件描述符
- 通过 Binder 传递文件描述符(File Descriptor),然后在服务端直接读取文件内容。这种方式可以传输大量数据,但需要服务端和客户端都支持文件描述符的处理
- 使用其他通信机制
- 对于非常大的数据传输,可以考虑使用其他通信机制,如 Socket通信、共享内存等。
33.6 安全性和权限控制
33.6.1 权限控制
- 权限声明:在服务端的
AndroidManifest.xml文件中声明权限,限制访问服务端的客户端<service android:name=".CalcService"> <intent-filter> <action android:name="com.example.binderdemo.CalcService" /> </intent-filter> <meta-data android:name="android.permission.BIND_CALC_SERVICE" android:resource="@xml/calc_service" /> </service> - 权限检查:在服务端的 Binder 实现中进行权限检查
@Override public int add(int a, int b) throws RemoteException { if (getContext().checkCallingOrSelfPermission("com.example.binderdemo.BIND_CALC_SERVICE") != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Permission denied"); } return a + b; }
33.6.2 数据加密
- 数据加密:可以对传输的数据进行加密,确保数据的安全性
// 客户端 byte[] encryptedData = encrypt(data); iCalc.sendData(encryptedData); // 服务端 byte[] decryptedData = decrypt(data);
33.7 性能优化
- 减少数据量:尽量减少传输的数据量,避免不必要的数据传输
- 异步通信:使用异步通信方式,提高通信效率
- 缓存:在服务端缓存常用数据,避免重复计算和传输
33.8 binder 调用失败的原因总结
DeadObjectException目标进程已经崩溃或被杀死RemoteException远程调用过程中发生错误,可能是网络问题、目标服务未启动或目标服务崩溃等SecurityException调用方没有权限NullpointerException调用Binder 对象时空指针了TransactionTooLargeException传递的数据量过大IllegalArgumentException参数异常TimeoutException远程调用超时ClassNotFoundException找不到类BadParcelableException传递的 Parcel 对象序列化或者反序列化失败
34. Cronet 通用网络库
简述:Cronet 是一个由 Chrome 团队开发的高性能网络堆栈,旨在为 Android 应用提供高效、可靠的网络通信能力。Cronet 基于 Chrome 的网络堆栈实现,支持多种网络协议,包括 HTTP/1.1、HTTP/2、QUIC 和 HTTP/3。下面是关于 Cronet 的详细解释,包括其基本概念、特点、使用方法和应用场景。
34.1 基本概念
34.1.1 Cronet 是什么
- Cronet:Cronet是一个高性能的网络堆栈,用于 Android 应用。它基于 Chrome 的网络堆栈实现,提供了高效的网络请求处理能力
- Chrome 网络堆栈:Chrome 浏览器的网络堆栈经过多年的优化,支持多种网络协议和功能,如 HTTP/1.1、HTTP/2、QUIC 和 HTTP/3
34.1.2 主要特点
- 高性能:Cronet 通过多路复用、连接池和异步请求等技术,显著提高了网络请求的性能。
- 支持多种协议:支持 HTTP/1.1、HTTP/2、QUIC 和 HTTP/3 ,确保应用可以使用最新的网络协议
- 易用性:提供简单易用的 API,方便开发者集成到 Android 应用中
- 安全性:支持 HTTPS 和其他安全协议,确保数据传输的安全性
- 可扩展性:支持自定义网络请求和响应处理,满足不同应用的需求。
34.2 使用方法
34.2.1 添加依赖
在 build.gradle 文件中添加 Cronet 的依赖:
dependencies {
implementation 'org.chromium.net:cronet:93.1.4577.62'
}
34.2.2 初始化 Cronet
在应用启动时初始化 Cronet:
import org.chromium.net.CronetEngine;
public class MyApplication extends Application {
private CronetEngine cronetEngine;
@Override
public void onCreate() {
super.onCreate();
// 创建 CronetEngine 实例
cronetEngine = new CronetEngine.Builder(this)
.enableHttp2(true)
.enableQuic(true)
.build();
}
public CronetEngine getCronetEngine() {
return cronetEngine;
}
}
34.2.3 发起网络请求
使用 UrlRequest 类发起网络请求:
import org.chromium.net.UrlRequest;
import org.chromium.net.UrlRequestCallback;
public class MainActivity extends AppCompatActivity {
private CronetEngine cronetEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyApplication app = (MyApplication) getApplication();
cronetEngine = app.getCronetEngine();
// 创建 UrlRequest
UrlRequest request = cronetEngine.newUrlRequestBuilder("https://example.com/api/data", new UrlRequestCallback() {
@Override
public void onRedirectReceived(UrlRequest request, UrlResponseInfo info, String newLocationUrl) {
// 处理重定向
request.followRedirect();
}
@Override
public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
// 处理响应开始
if (info.getHttpStatusCode() == 200) {
request.read(new byte[1024]);
} else {
request.cancel();
}
}
@Override
public void onReadCompleted(UrlRequest request, UrlResponseInfo info, byte[] bytes) {
// 处理读取完成
String response = new String(bytes);
Log.d("Cronet", "Response: " + response);
request.read(new byte[1024]);
}
@Override
public void onSuccess(UrlRequest request, UrlResponseInfo info) {
// 处理请求成功
Log.d("Cronet", "Request succeeded");
}
@Override
public void onFailure(UrlRequest request, UrlResponseInfo info, CronetException error) {
// 处理请求失败
Log.e("Cronet", "Request failed: " + error.getMessage());
}
}, new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
}).build();
// 发起请求
request.start();
}
}
34.3 主要功能
1. 多路复用:HTTP/2 和 HTTP/3 :支持多路复用,允许多个请求共享同一个连接,减少连接建立的开销
2. 连接池:连接复用:Cronet 使用连接池管理网络连接,复用已建立的连接,提高性能
3. 安全性:
HTTPS:支持 HTTPS 协议,确保数据传输的安全性
证书校验:支持自定义证书校验,增强安全性
4. 异步请求:Cronet 支持异步请求处理,不会阻塞主线程,提供应用的响应性
5. 自定义请求和响应处理
请求头:支持自定义请求头,满足不同场景的需求
响应处理:支持自定义响应处理逻辑,如数据解析和错误处理
34.4 应用场景
1. 高性能网络应用
数据密集型应用:如视频流、在线游戏等,需要高效、低延迟的网络通信
实时应用:如即时通讯、实时数据传输等,需要快速响应网络请求
2. 多协议支持
多种网络协议:支持 HTTP/1.1、HTTP/2、QUIC 和 HTTP/3,满足不同网络环境的需求
3. 安全性要求高的应用
金融应用:如在线支付、银行应用等,需要确保数据传输的安全性
隐私保护:如健康应用、个人数据管理等,需要保护用户数据的隐私
总结
Cronet 是一个高性能的网络堆栈,基于 Chrome 的网络堆栈实现
支持多种网络协议和功能
通过多路复用、连接池和异步请求等技术,Cronet 提供了高效的网络请求处理能力
开发者可以轻松地将 Cronet 集成到 Android 应用中,提高应用的性能和可靠性
36. OKHTTP 通用网络库
简述:
OKHTTP 是一个高效的 HTTP 客户端,由 Square 公司开发并维护。
它被广泛用于 Android 和 Java 应用程序中,提供了一种简单且高效的方式来发送和接收 HTTP 请求。
OKHTTP 支持多种功能,包括连接池、缓存、重试和恢复等。
36.1 基本概念
- 什么是 OKHTTP
1. OKHttp:OKHttp 是一个高效的 HTTP 客户端库,用于发送和接收 HTTP 请求。它支持 HTTP/1.1 和 HTTP/2 协议,并且可以通过扩展支持 HTTP/3 2. HTTP 客户端:HTTP 客户端用于与服务器进行通信,发送请求并接收响应 - 主要特点
1. 高性能:OKHttp 通过连接处、多路复用和异步请求等技术,提高了网络请求的性能 2. 支持多种协议:支持 HTTP/1.1、HTTP/2 和 HTTP/3,确保应用可以使用最新的网络协议 3. 易用性:提供简单易用的 API,方便开发者集成到应用中 4. 缓存:支持相应缓存,减少不必要的网络请求,提高应用性能 5. 重试和恢复:自动处理网络连接失败和部分数据传输失败,提高请求的成功率 6. 拦截器:支持自定义拦截器,方便开发者对请求和响应进行处理 7. 安全性:支持 HTTPS 和其他安全协议,确保数据传输的安全性
36.2 使用方法
- 添加依赖:在
build.gradle文件中添加 OKHttp 的依赖:dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.3' } - 创建 OKHttpClient 实例
import okhttp3.OkHttpClient; public class MyApplication { private OkHttpClient client; public MyApplication() { // 创建 OkHttpClient 实例 client = new OkHttpClient(); } public OkHttpClient getClient() { return client; } } - 发起同步请求
import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class MainActivity { private OkHttpClient client; public MainActivity() { client = new OkHttpClient(); } public void sendSyncRequest() { // 创建请求对象 Request request = new Request.Builder() .url("https://api.example.com/data") .build(); // 发起同步请求 try (Response response = client.newCall(request).execute()) { if (response.isSuccessful()) { String responseBody = response.body().string(); System.out.println("Response: " + responseBody); } else { System.out.println("Request failed: " + response.code()); } } catch (Exception e) { e.printStackTrace(); } } } - 发起异步请求
import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Response; public class MainActivity { private OkHttpClient client; public MainActivity() { client = new OkHttpClient(); } public void sendAsyncRequest() { // 创建请求对象 Request request = new Request.Builder() .url("https://api.example.com/data") .build(); // 发起异步请求 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { String responseBody = response.body().string(); System.out.println("Response: " + responseBody); } else { System.out.println("Request failed: " + response.code()); } } }); } }
36.3 主要功能
1. 连接池------连接复用:OKHttp 使用连接池管理网络连接,复用已建立的连接,减少连接建立的开销,提高性能
2. 多路复用-----HTTP/2:支持 HTTP/2 协议的多路复用,允许多个请求共享同一个连接,减少连接建立的开销
3. 缓存--------响应缓存:OKHttp 支持响应缓存,减少不必要的网络请求,提高应用性能
4. 重试和恢复---自动重试:自动处理网络连接失败和部分数据传输失败,提高请求的成功率
5. 拦截器-------自定义拦截器:支持自定义拦截器,方便开发者对请求和响应进行处理,如日志记录、请求头添加等
6. 安全性 ----- HTTPS, 证书校验
自定义拦截器实例:
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MyApplication {
private OkHttpClient client;
public MyApplication() {
// 创建拦截器
Interceptor loggingInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
System.out.println("Sending request: " + request.url());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
System.out.println("Received response: " + response.code() + " in " + (t2 - t1) / 1e6d + "ms");
return response;
}
};
// 创建 OkHttpClient 实例并添加拦截器
client = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build();
}
public OkHttpClient getClient() {
return client;
}
}
36.4 应用场景
高性能网络应用
数据密集型应用:如视频流、在线游戏等,需要高效、低延迟的网络通信
实施应用:如即时通讯、实时数据传输等,需要快速响应网络请求
高协议支持:
多种网络协议:支持 HTTP/1.1、HTTP/2、HTTP/3,满足不同网络环境的需求
安全性要求高的应用:
金融应用:如在线支付、银行应用等,需要确保数据传输的安全性
隐私保护:如健康应用、个人数据管理等,需要保护用户数据的隐私
36.5 总结
OKHttp 是一个高效、易用的 HTTP 客户端库,支持多种网络协议和功能。
通过连接池、多路复用、缓存、重试和恢复等技术,OKHttp 提供了高效的网络请求处理能力。
开发者可以轻松地将 OKHttp 集成到 Android 和 Java 应用中,提高应用的性能和可靠性。
37. AFNetworking 通用网络库
简介
AFNetworking 是一个非常流行的 iOS 和 MacOS 平台上的网络库,由 GitHub 的 Mattt Thompson 创建并维护。它基于 Foundation 框架的 NSURLSession 构建,提供了简单易用的 API 和丰富的功能,使得开发能够高效地处理网络请求和响应。
37.1 基本概念
1、什么是 AFNetworking?
AFNetworking:是一个 IOS 和 macOS 平台上的网络库,用于发送和接收 HTTP 请求。它基于 Foundation 框架的 `MSURLSession` 构建,提供了简单易用的 API 和丰富的功能。
网络库:网络库用于与服务器进行通信,发送请求并接收响应
2、主要特点
1. 简单易用:提供简单易用的的 API,方便开发者快速集成和使用
2. 高性能:基于 NSURLSession 构建,支持异步请求和连接池,提高网络请求的性能
3. 支持多种协议:支持 HTTP 和 HTTPS 协议,确保数据传输的安全性
4. 丰富的功能:支持文件上传、下载、请求重试、缓存等高级功能
5. 拦截器:支持自定义拦截器,方便开发者对请求和响应进行处理
6. 社区支持:拥有活跃的社区和丰富的文档,方便开发者学习和解决问题
37.2 使用方法
1、添加依赖:使用 CocoaPods 添加 AFNetworking 依赖:
1. 在 prdfile 中添加一下内容
pod 'AFNetworking', '~> 4.0'
2. 在终端运行以下命令来安装依赖:
pod install
2、发起 GET 请求
#import <AFNetworking/AFNetworking.h>
- (void)sendGETRequest {
NSString *urlString = @"https://api.example.com/data";
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:urlString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(@"Response: %@", responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
3、发起 POST 请求
#import <AFNetworking/AFNetworking.h>
- (void)sendPOSTRequest {
NSString *urlString = @"https://api.example.com/data";
NSDictionary *parameters = @{@"key1": @"value1", @"key2": @"value2"};
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager POST:urlString parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(@"Response: %@", responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
4、文件上传
#import <AFNetworking/AFNetworking.h>
- (void)uploadFile {
NSString *urlString = @"https://api.example.com/upload";
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"image.jpg"], 0.5);
[manager POST:urlString parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:@"file" fileName:@"image.jpg" mimeType:@"image/jpeg"];
} progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(@"Response: %@", responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
5、文件下载
#import <AFNetworking/AFNetworking.h>
- (void)downloadFile {
NSString *urlString = @"https://api.example.com/download";
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString *destinationPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
destinationPath = [destinationPath stringByAppendingPathComponent:@"downloaded_file"];
[manager downloadTaskWithURL:[NSURL URLWithString:urlString] progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
return [NSURL fileURLWithPath:destinationPath];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"File downloaded to: %@", filePath);
}
}];
}
37.3 主要功能
1. 异步请求 异步处理:AFNetworking 支持异步请求处理,不会阻塞主线程,提高应用的响应性
2. 请求重试 自动重试:支持请求重试,自动处理网络连接失败和部分数据传输失败,提高请求的成功率
3. 缓存 响应缓存:支持响应缓存,减少不必要的网络请求,提高应用性能
4. 拦截器 自定义拦截器:支持自定义拦截器,方便开发者对请求和响应进行处理,如日志记录、请求头添加等
5. 安全性 HTTPS/证书校验
自定义拦截器实例:
#import <AFNetworking/AFNetworking.h>
- (void)setupInterceptors {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[manager setRequestInterceptor:^ NSURLRequest * _Nullable(NSURLRequest * _Nonnull request) {
// 自定义请求拦截器
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[mutableRequest setValue:@"Custom-Header" forHTTPHeaderField:@"X-Custom-Header"];
return mutableRequest;
}];
[manager setResponseInterceptor:^ id _Nullable(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
// 自定义响应拦截器
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"Response: %@", responseObject);
}
return responseObject;
}];
}
37.4 应用场景
高性能网络应用
数据密集型应用:如视频流、在线游戏等,需要高效、低延迟的网络通信
实施应用:如即时通讯、实时数据传输等,需要快速响应网络请求
高协议支持:
多种网络协议:支持 HTTP/1.1、HTTP/2、HTTP/3,满足不同网络环境的需求
安全性要求高的应用:
金融应用:如在线支付、银行应用等,需要确保数据传输的安全性
隐私保护:如健康应用、个人数据管理等,需要保护用户数据的隐私
37.5 总结
AFNetworking 是一个高效、易用的 iOS 和 macOS 平台上的网络库,提供了简单易用的 API 和丰富的功能。
通过异步请求、请求重试、缓存、拦截器和安全性等技术,AFNetworking 提供了高效的网络请求处理能力。
开发者可以轻松地将 AFNetworking 集成到应用中,提高应用的性能和可靠性。
38. TCP/IP、UDP、HTTP、HTTPS、QUIC、P2P、PCDN
38.1 TCP/IP(传输控制协议/互联网协议)
1、概述
1. TCP/IP:传输控制协议/互联网协议,是互联网的基础协议,定义了数据如何在网络中传输
2. 分层模型:TCP/IP 模型分为四层,分别是 应用层、传输层、网络层和链路层
2、主要特点
1. 连接导向:TCP 是连接导向的协议,提供可靠的数据传输
2. 数据包重传:自动重传丢失或损坏的数据包
3. 流量控制:通过滑动窗口机制控制数据传输速率,防止拥塞
4. 拥塞控制:动态调整传输速率,防止网络拥塞
3、应用
1. Web 浏览:HTTP、HTTPS 协议使用 TCP
2. 文件传输:FTP、SFTP 协议使用 TCP
3. 电子邮件:SMTP、POP3、IMAP 协议使用 TCP
38.2 UDP(用户数据报协议)
1、概述
1. UDP:用户数据报协议,是一种无连接的协议,提供不可靠的数据传输
2. 无连接:发送数据前不需要建立连接,速度快但不保证数据的可靠传输
2、主要特点
1. 轻量级:开销小,适合实时应用
2. 无序传输:数据包按发送顺序传输,但不保证到达顺序
3. 无重传机制:不重传丢失的数据包
3、应用
1. 实时应用:如在线视频、语音通话、在线游戏
2. DNS查询:域名解析通常使用 UDP
38.3 HTTP(超文本传输协议)
1、概述
1. HTTP:超文本传输协议,用于在客户端和服务器之间传输超文本信息
2. 无状态:每个请求都是独立的,服务器不保留会话状态
2、主要特点
1. 请求-响应模型:客户端发起请求,服务器响应
2. 方法:常见的方法有 GET、POST、PUT、DELETE 等
3. 状态码:用于表示请求的结果,如 200 OK、404 Not Found 等
3、应用
1. Web 浏览:浏览器和服务器之间的数据传输
2. API 调用:RESTful API 使用 HTTP
38.4 HTTPS(安全超文本传输协议)
1、概述
1. HTTPS:安全超文本传输协议,是 HTTP 的安全版本,通过 SSL/TLS 协议进行数据加密
2. 加密:确保数据传输的安全性,防止数据被窃听或篡改
2、主要特点
1. 加密传输:数据在传输过程中被加密,提高安全性
2. 证书:使用数字证书验证服务器身份
3. 端口:默认使用 443 端口
3、应用
1. 安全通信:银行、电子商务、在线支付等需要高度安全的场景
38.5 QUIC(快速 UDP 互联网连接)
1、概述
1. QUIC:快速 UDP 互联网连接,是一种基于 UDP 的传输层协议,旨在减少网络延迟和提高性能
2. 设计目标:减少连接建立时间,提高数据传输效率、减少丢包影响
2、主要特点
1. 多路复用:多个流可以共享一个连接,减少延迟
2. 连接迁移:支持连接在不同网络之间迁移,提高移动设备的体验
3. 加密:内置加密机制,提供安全的数据传输
4. 无连接:基于 UDP,减少握手时间
3、应用
1. Web 性能优化:Google 和其他公司广泛使用 QUIC 优化 Web 性能
2. 实时应用:如在线视频、语音通话
38.6 P2P(点对点)
1、概述
1. P2P:点对点网络,是一种分布式网络架构,节点之间直接通信,没有中心服务器
2. 去中心化:每个节点既是客户端又是服务器
2、主要特点
1. 分布式:资源分布在多个节点上,提高系统可用性和可靠性
2. 去中心化:没有单一的控制点,减少单点故障
3. 资源分享:节点直接直接分享资源,提高资源利用效率
3、应用
1. 文件分享:如 BitTorrent
2. 分布式计算:如 BOINC
38.7 PCDN(内容分发网络)
1、概述
1. PCDN:内容分发网络,是一种将内容分发到全球多个节点的网络架构,以提高内容的访问速度和可靠性
2. 边缘节点:内容存储在靠近用户的边缘节点,减少传输延迟
2、主要特点
1. 内容缓存:在边缘节点缓存内容,减少服务器负载
2. 负载均衡:通过负载均衡技术,优化内容分发
3. 全球覆盖:覆盖全球多个地区,提高内容的可用性
3、应用
1. 视频流:如 Netflix、YouTube
2. Web应用:提高静态资源的加载速度
38.8 总结
网络协议是确保数据在网络中可靠传输的基础。
TCP/IP 提供了互联网的基础架构
HTTP 和 HTTPS 用于 Web 通信
UDP 适用于实时应用
QUIC 优化了 Web 性能
P2P 实现了去中心化的资源分享
PCDN 提高了内容分发的效率
39. 异步网络编程
39.0 多线程编程和并发模型
1、基本概念
1. 进程:进程是操作系统尽心该资源分配和调度的基本单位,每个进程有独立的地址空间、内存、数据栈等
2. 线程:线程是进程中的执行单元,多个线程可以共享进程的资源,如内存、文件描述符等。线程是操作系统调度的最小单位
3. 并发:并发是指多个任务在同一时间段内交替执行,但不一定是同时执行。操作系统通过快速切换线程或进程来实现并发
4. 并行:并行是指多个任务在同一时间点上同时执行,通常需要多核处理器来实现
2、多线程编程
优势
1. 资源利用率:多线程可以更好地利用多核处理器,提高程序的性能
2. 响应性:多线程可以提高程序的响应性,特别是处理 I/O 操作和用户交互时
3. 模块化:多线程编程可以将复杂任务分解为多个独立的线程,提高代码的可维护性和可扩展性
挑战
1. 同步问题:多线程共享资源时,需要处理同步问题,防止数据竞争和死锁
2. 调试困难:多线程程序的调试比单线程程序更复杂,因为线程的执行顺序和时间点难以预测
3. 性能开销:线程的创建、切换和销毁会带来一定的性能开销。
3、常见的并发模型
3.1 多线程模型
用户级线程:由应用程序管理的线程,操作系统不直接调度
内核级线程:由操作系统管理的线程,操作系统负责调度
3.2 事件驱动模型
事件循环:通过一个事件循环来处理异步事件,如 I/O 操作、定时器等
回调函数:事件发生时,调用相应的回调函数处理事件
3.3 协程
协程:协程是用户级的轻量级线程,可以在一个线程内实现并发
协作调度:协程之间的切换由程序员控制,而不是由操作系统调度
3.4 消息传递模型
进程间通信:通过消息传递的方式实现进程间的通信和同步
Actor 模型:每个 Actor 是一个独立的实体,通过消息传递进行通信,Actor 之间没有共享状态
4、同步机制
4.1 互斥锁
互斥锁:用户保护共享资源,确保同一时间只有一个线程可以访问
锁的粒度:锁的粒度越细,性能越好,但实现复杂度越高
4.2 信号量
信号量:用于控制对共享资源的访问,可以允许多个s线程同时访问
计数信号量:表示可用资源的数量,线程在访问资源时会减少计数,释放资源时会增加计数
4.3 条件变量
条件变量:用于线程之间的同步,线程可以在某个条件满足时被唤醒
等待和通知:线程可以等待某个条件满足,其他线程可以通知等待的线程
4.4 读写锁(RWLock)
读写锁:荀彧多个读线程同时访问,单只允许一个写线程访问
读优先和写优先:可以选择读优先或写优先的策略
39.1 线程池
简述:
线程池是一种常用的多线程编程技术,用于管理和复用一组预先创建的线程,以提高程序的性能和资源利用率。线程池可以有效地减少线程的创建和销毁开销,提高任务的处理速度。
1、基本概念
1. 什么是线程池?
线程池:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务
线程复用:线程池中的线程可以被复用,而不是每次任务执行时都创建和销毁线程
2. 主要组成部分
线程池:管理一组线程的集合
任务队列:存储待处理任务的队列
工作线程:从任务队列中取出任务并执行的线程
同步机制:用于线程之间的同步,如互斥锁、条件变量等
2、工作原理
1. 任务提交
提交任务:客户端任务提交到任务队列中
任务队列:任务队列存储待处理的任务,通常是一个线程安全的队列
2. 任务执行
工作线程:线程池中的工作线程从任务队列中取出任务并执行
任务调查:线程池根据任务队列中的任务和工作线程的空闲情况,动态调度任务
3. 任务完成
任务完成:工作线程完成任务后,可以继续从任务队列中取出新的任务
线程复用:线程池中的线程可以被服用,减少线程的创建和销毁开销
3、优势
1. 减少线程创建和销毁开销
线程创建开销:每次创建线程都需要分配资源和初始化,开销较大
线程销毁开销:每次销毁线程都需要释放资源,开销较大
线程复用:线程池中的线程可以被复用,减少创建和销毁线程的开销
2. 提高响应速度
快速响应:线程池中的线程已经处于就绪状态,可以快速响应新的任务
减少延迟:减少任务的等待时间,提高任务的处理速度
3. 控制资源消耗
资源限制:可以限制线程池中现成的数量,防止过多的线程消耗系统资源
资源管理:可以动态调整线程池的大小,根据系统负载进行资源管理
4、常见实现 -- Java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("All tasks finished");
}
}
class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s) {
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
processCommand();
System.out.println(Thread.currentThread().getName() + " End.");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
39.2 libevent、 asio、 libuv
libevent
1、基本概念
libevent:一个事件驱动的网络库,用于处理多个并发连接。它提供了一种跨平台的方式来处理 I/O 事件、定时器事件和信号事件
2、主要特点
高性能:使用高效的事件通知机制,如 `epoll`(Linux)、`kqueue`(BSD)、poll 和 select
跨平台:支持多种操作系统,包括 LInux、Windows、macOS 和 各种 Unix
简单易用:提供了一套简单且一致的 API,使得开发人员可以轻松地编写事件驱动的网络应用程序
3、主要功能
事件管理:事件注册、事件删除、事件激活
I/O 事件:文件描述符的读写事件
定时器事件:在特定时间或间隔后触发的事件
信号事件:处理信号的事件
asio
1、基本概念
asio:一个跨平台的异步 I/O 库,是 Boost.Asio 的一部分,也可以独立使用。它提供了一种高效的方式来处理网络通信和低级 I/O 操作
2、主要特点
异步编程:支持异步 I/O 操作,可以编写高效的并发应用程序
跨平台:支持多种操作系统,包括 Linux、Windows、macOS和各种 Unix 系统
灵活的API:提供了丰富的API,支持多种网络协议和 I/O 操作
3、主要功能
异步 I/O:支持异步读写、异步连接和异步接受连接
定时器:支持多种定时器,包括单词定时器和周期定时器
网络协议:支持 TCP、UDP、ICMP 多种网络协议
信号处理:处理信号事件
libuv
1、基本概念
libuv:一个跨平台的一部 I/O 库,最初是为 Node.js 开发的。它提供了一种高效的方式来处理网络通信、文件系统操作、进程间通信等
2、主要特点
高性能:使用高效的事件通知机制:如 epoll、kqueue、IOCP
跨平台:支持多种操作系统,包括 Linux、Windows、macOS和各种 Unix 系统
轻量级:设计简洁,依赖少,适合嵌入式系统和高性能服务器
3、主要功能
异步 I/O:支持异步读写、异步连接和异步接受连接
定时器:支持多种定时器,包括单次定时器和周期定时器
文件系统操作:支持异步文件操作
进程管理:支持进程创建和进程间通信
信号处理:处理信号事件
对比
1、性能
libevent:使用高效的事件通知机制,性能较好,但可能不如 libuv 和 asio。
asio:支持异步编程,性能良好,但可能在某些操作系统上不如 libuv 优化得那么好。
libuv:设计为高性能,特别是在 Node.js 中,性能优化非常好。
2、跨平台
libevent:跨平台,支持多种操作系统。
asio:跨平台,支持多种操作系统。
libuv:跨平台,支持多种操作系统,特别是对 Windows 的支持较好。
3、API
libevent:API 简单易用,但功能相对较少。
asio:API 丰富,支持多种网络协议和 I/O 操作,但学习曲线较陡。
libuv:API 设计简洁,功能全面,适合嵌入式系统和高性能服务器。
4、使用场景
libevent:适用于简单的网络服务器和客户端应用程序。
asio:适用于需要复杂网络通信和高性能 I/O 操作的应用程序。
libuv:适用于需要高性能和多种功能的网络应用程序,特别是 Node.js 开发。
40. HTTPDNS、全站加速、CDN
简述:
HTTPDNS 是一种通过 HTTP 协议来解析域名的技术,旨在解决传统 DNS 解析中的一些问题,如域名劫持、DNS污染和解析延迟等。HTTPDNS 通过将域名解析请求发送到 HTTP 服务器,获取 IP 地址,从而提供更可靠和快速的域名解析服务。
HTTPDNS
1、基本概念
1. 什么是 HTTPDNS?
HTTPDNS:通过 HTTP 协议来解析域名的技术,提供更可靠和快速的域名解析服务
域名解析:将域名转换为 IP 地址的过程
2. 传统 DNS 的问题
域名劫持:DNS 服务器被恶意劫持,返回错误的 IP 地址
DNS污染:DNS 缓存中存储了错误的 IP 地址
解析延迟:DNS 解析过程中的延迟影响应用程序的性能
2、工作原理
1. 域名解析流程
1. 客户端发起请求:客户端通过 HTTP 协议向 HTTPDNS 服务器发送域名解析请求
2. HTTPDNS 服务器处理请求:HTTPDNS 服务器根据请求中的域名,查询其内部的 DNS 缓存或直接查询权威 DNS 服务器,获取 IP 地址
3. 返回解析结果:HTTPDNS 服务器将获取到的 IP 地址通过 HTTP 响应返回给客户端
4. 客户端使用 IP 地址:客户端使用返回的 IP 地址进行网络通信
2. 与传统 DNS 的区别
1. 协议:HTTPDNS 使用 HTTP 协议,传统 DNS 使用 UDP 或 TCP 协议
2. 可靠性:HTTPDNS 通过 HTTPS 协议传输数据,更加安全可靠
3. 缓存:HTTPDNS 服务器可以更灵活地管理缓存,减少 DNS 污染的影响
4. 响应时间:HTTPDNS 服务器通常部署在靠近客户端的地理位置,减少解析延迟
3、优势
1. 安全性
防止劫持:HTTPDNS 通过 HTTPS 协议传输数据,防止中间人共计和域名劫持
减少污染:HTTPDNS 服务器可以更灵活地管理缓存,减少 DNS 污染的影响
2. 性能
减少延迟:HTTPDNS 服务器通常部署在靠近客户端的地理位置,减少解析延迟
快速响应:HTTPDNS 服务器可以快速响应客户端的请求,提高应用程序的性能
3. 灵活性
自定义解析:HTTPDNS 服务器可以根据业务需求,自定义域名解析规则
负载均衡:HTTPDNS 服务器可以实现更细粒度的负载均衡,提高服务的可用性
4、应用场景
1. 移动应用
防止劫持:移动应用中使用 HTTPDNS 可以防止 DNS 劫持,提高用户访问的安全性
快速响应:HTTPDNS 可以减少 DNS 解析的延迟,提高移动应用的性能
2. 云服务
负载均衡:云服务中使用 HTTPDNS 可以实现更细粒度的负载均衡,提高服务的可用性
自定义解析:HTTPDNS 可以根据业务需求,自定义域名解析规则,提高服务的灵活性
3. 游戏应用
防止劫持
减少延迟:提高游戏的流畅性
全站加速
简述:
全站加速(Whole Site Acceleration,简称 WSA)是一种通过优化网络传输和内容分发,提高网站访问速度和用户体验的技术。全站加速通过 CDN(内容分发网络)、缓存、压缩、智能路由等多种技术手段,确保用户能够快速访问网站内容,无论用户位于世界的哪个角落。
1、基本概念
1. 什么是全站加速?
全站加速:通过多种技术手段优化网站的访问速度,提高用户体验
目标:确保用户能够快速、稳定地访问网站内容,无论用户位于世界的那个角落
2. 传统加速方式的局限
单一加速:传统的加速方式通常只针对特定类型的资源(如静态资源)进行优化,无法全面覆盖网站的所有内容
性能瓶颈:传统的加速方式可能在高并发访问时出现性能瓶颈,影响用户体验
2、工作原理
1. 内容分发网络(CDN)
CDN:通过再全球范围内部署多个节点,将网站内容缓存到离用户最近的节点,减少数据传输距离,提高访问速度
缓存:CDN 节点缓存网站的静态资源(如图片、CSS、JS文件),用户访问时直接从缓存中获取,减少服务器负载
智能路由:CDN 通过智能路由技术,选择最佳路径将用户请求路由到最近的节点,减少网络延迟
2. 动态内容加速
动态内容:对于动态内容(如动态生成的 HTML 页面、API请求等),全站加速可以通过以下技术手段进行优化:
缓存:动态内容也可以进行缓存、但缓存策略需要更加灵活,确保内容的新鲜度
边缘计算:在 CDN 节点上部署边缘计算节点,处理部分动态请求,减少回源次数
智能压缩:对动态内容进行压缩,减少传输数据量,提高传输速度
3. 静态内容加速
静态内容:对于静态内容(如图片、CSS、JS文件等),全站加速通过一下技术手段进行优化:
缓存:将静态内容缓存到 CDN 节点,用户访问时直接从缓存中获取
压缩:对于静态内容进行压缩,减少传输数据量,提高传输速度
懒加载:对于图片等资源,使用懒加载技术,减少初始加载时间
4. 安全性
DDoS防护:CDN节点可以提供 DDoS 防护,保护网站免受攻击
HTTPS:支持 HTTPS 传输,确保数据传输的安全性
3、优势
3.1 提高访问速度
减少网络延迟:通过 CDN 节点和智能路由技术,减少数据传输距离和网络延迟。
减少服务器负载:通过缓存技术,减少服务器的处理请求量,提高服务器性能。
3.2 提高用户体验
快速响应:用户能够快速访问网站内容,提高用户体验。
稳定性:通过多节点部署和智能路由技术,确保网站的高可用性和稳定性。
3.3 降低成本
减少带宽成本:通过缓存技术,减少服务器的带宽消耗,降低带宽成本。
减少服务器成本:通过减少服务器的处理请求量,降低服务器成本。
4、应用场景
4.1 电子商务
提高转化率:用户能够快速访问商品页面,提高购买转化率。
提高用户体验:用户能够快速浏览商品图片和详情,提高用户体验。
4.2 在线教育
提高学习体验:学生能够快速访问课程内容,提高学习体验。
稳定访问:通过多节点部署和智能路由技术,确保课程的高可用性和稳定性。
4.3 新闻门户
提高访问速度:用户能够快速访问新闻页面,提高访问速度。
提高用户体验:用户能够快速浏览新闻图片和视频,提高用户体验。
4.4 游戏应用
减少延迟:用户能够快速访问游戏资源,减少延迟,提高游戏体验。
提高稳定性:通过多节点部署和智能路由技术,确保游戏的高可用性和稳定性。
5、实现方法
5.1 选择全站加速服务提供商
CDN 服务商:选择知名的 CDN 服务商,如阿里云、腾讯云、AWS 等,提供全站加速服务。
定制化服务:根据业务需求,选择定制化的全站加速服务,如动态内容加速、边缘计算等。
5.2 配置全站加速
域名解析:将网站域名解析到 CDN 服务商的域名。
缓存策略:配置缓存策略,确保静态内容和动态内容的缓存效果。
智能路由:配置智能路由策略,确保用户请求能够被路由到最近的节点。
安全设置:配置 DDoS 防护和 HTTPS 传输,确保数据传输的安全性。
5.3 监控和优化
性能监控:通过监控工具,实时监控网站的访问速度和性能。
日志分析:通过日志分析,优化缓存策略和路由策略,提高性能。
6、示例
1.登录阿里云控制台:
访问阿里云官网,登录控制台。
2.创建 CDN 加速域名:
进入 CDN 服务页面,点击“添加域名”。
填写加速域名、源站信息等配置项。
选择“全站加速”类型。
3.配置缓存策略:
在 CDN 域名管理页面,选择已创建的加速域名。
进入“缓存配置”页面,配置静态和动态内容的缓存策略。
4.配置智能路由:
在 CDN 域名管理页面,选择已创建的加速域名。
进入“智能调度”页面,配置智能路由策略。
5.配置安全设置:
在 CDN 域名管理页面,选择已创建的加速域名。
进入“安全配置”页面,配置 DDoS 防护和 HTTPS 传输。
6.域名解析:
在域名解析页面,将网站域名解析到 CDN 服务商的 CNAME 地址。
7、总结
全站加速通过多种技术手段优化网站的访问速度,提高用户体验。
通过 CDN、缓存、压缩、智能路由等多种技术手段,确保用户能够快速、稳定地访问网站内容,无论用户位于世界的哪个角落。
通过理解全站加速的工作原理和优势,开发人员可以更好地利用它来提高网站的性能和用户体验。








浙公网安备 33010602011771号