手机从开机到上网的关键步骤,包括ConnectivityService初始化、Phone进程启动、SIM卡加载、APN配置、PS附着、DataCall建立、NetworkAgent注册以及网络状态广播等环节
手机不能上网原因分析及检测手段
| 问题阶段 | 具体原因/表现 | 检测手段/说明 |
|---|---|---|
| 一、数据链路未建立 (托盘无数据图标) | 1. SIM卡状态异常:未加载完成、未识别(信号格显示“x”) 2. 开关/设置问题: - 系统设置中数据开关未开启 - 飞行模式开启或Radio关闭 - 漫游状态下未启用漫游数据 3. 网络状态限制: - PS(数据业务)未成功附着网络 - CS(语音业务) 正在进行,与PS业务冲突 - PhoneState非激活(Inactive)状态 - 网络侧限制了PS业务 4. APN配置问题:手机中没有有效的APN配置 | 1. 检查SIM卡:进入设置->双卡和移动网络,查看是否读到SIM卡;尝试重新插拔SIM卡。 2. 检查开关:在同上路径,确认移动数据开关已开启。 3. 检查APN:进入设置->双卡和移动网络->SIM卡->接入点名称(APN) ,若列表为空,需手动添加正确APN。 |
| 二、数据链路建立失败 (尝试连接但失败) | 1. 网络制式限制:手机注册在仅支持语音的旧网络(如CDMA、GSM),导致数据建立失败。 2. APN类型不匹配:网络要求特定的IP类型(如IPv4 only),但手机配置了IPv4v6等不匹配类型。 3. 弱信号场景:信号强度太弱,导致数据连接建立过程失败。 | 此阶段问题较为复杂,通常需要分析系统日志(Log) 来具体定位是网络拒绝还是终端配置原因。 |
| 三、数据链路已建立 (托盘有数据图标,但无法上网) | 1. 网络因素:弱信号、小区切换导致数据传输中断。 2. 表现:可以浏览网页、但微信等应用提示“无网络连接”。 | 1. 观察信号格:若在非弱信号区信号满格却无法上网,可尝试开关飞行模式以触发网络重连。 2. 问题定位:此情况基本为网络侧因素,同样需要分析Log进行深入定位。 |
╔════════════════════════════════════════════════════════════════════════════╗ ║ 手机从开机到上网的完整流程分析 ║ ║ (基于 Android Framework + Telephony + Connectivity 源码分析) ║ ╚════════════════════════════════════════════════════════════════════════════╝
【完整流程架构图】
手机开机 (Power ON) │ ├─→ 【阶段 1】Kernel & Init │ • 加载内核, 挂载文件系统 │ • 启动 init 进程 │ • 加载驱动程序(包括 RIL 驱动) │ ├─→ 【阶段 2】Zygote & SystemServer 启动 │ • Zygote 进程启动 │ • SystemServer 启动核心服务 │ • 启动 Phone 进程 (内含 RIL) │ ├─→ 【阶段 3】服务初始化 │ • ConnectivityService 初始化 │ • NetworkManagementService 初始化 │ • PhoneFactory 初始化 │ ├─→ 【阶段 4】网络连接管理 │ • NetworkAgent 注册 │ • SIM 卡读取 │ • 网络搜索 │ ├─→ 【阶段 5】蜂窝数据建立 │ • PS 附着 (Packet Switched Attach) │ • APN 配置 │ • DataCall 建立 │ • IP 地址分配 │ └─→ 【阶段 6】网络可用 • 网络验证 • 网络状态广播 • 应用可联网
════════════════════════════════════════════════════════════════════════════════
【阶段 1】Kernel & Init (~ 1-2 秒)
1.1 内核启动 ├─ 加载引导加载程序 (Bootloader) ├─ 初始化硬件 (内存、CPU 等) ├─ 加载内核镜像 └─ 启动根文件系统
1.2 Init 进程启动 (PID=1) ├─ 读取 init.rc 脚本 ├─ 创建根目录结构 ├─ 启动初始化服务 └─ 加载驱动程序 ├─ 蜂窝驱动 (modem driver) ├─ 网络驱动 (net driver) └─ 其他必要驱动
1.3 挂载文件系统 ├─ /system (只读) ├─ /vendor (只读) ├─ /data (可读写) └─ /dev, /proc, /sys (虚拟文件系统)
状态: 系统基础设施就绪, 等待上层应用启动
════════════════════════════════════════════════════════════════════════════════
【阶段 2】Zygote & SystemServer 启动 (~ 2-5 秒)
文件位置: • /frameworks_base/services/java/com/android/server/SystemServer.java • /frameworks_opt_telephony/src/java/com/android/internal/telephony/PhoneFactory.java
2.1 Zygote 进程启动 ├─ Init 进程启动 app_process (Zygote) ├─ Zygote 加载 Framework 库 ├─ 预加载系统类 (class preloading) ├─ 监听 socket 等待 Fork 请求 └─ Zygote Fork 出 SystemServer 进程
2.2 SystemServer 启动流程
代码示例:
```
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
// ... 初始化工作 ...
startBootstrapServices(t); // 启动引导服务
startCoreServices(t); // 启动核心服务
startOtherServices(t); // 启动其他服务
startApexServices(t); // 启动 APEX 服务
}
```
┌─────────────────────────────┐
│ startBootstrapServices │ (最早启动, 关键服务)
├─────────────────────────────┤
│ • ActivityManagerService │
│ • PackageManagerService │
│ • PowerManagerService │
│ • DisplayManagerService │
│ • UserManagerService │
│ • PermissionPolicyService │
│ • SensorService │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ startCoreServices │
├─────────────────────────────┤
│ • SystemConfigService │
│ • BatteryService │
│ • UsageStatsService │
│ • WebViewUpdateService │
└─────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ startOtherServices (主要网络服务) │
├─────────────────────────────────────┤
│ • NetworkManagementService │
│ • NetworkStatsService │
│ • NetworkPolicyManager │
│ • ConnectivityService ★★★ │
│ (ConnectivityServiceInitializer) │
└─────────────────────────────────────┘
2.3 Phone 进程启动 (com.android.phone) ├─ Zygote Fork 出 Phone 进程 ├─ Phone 进程主要任务: │ ├─ 创建 RIL 连接 (Radio Interface Layer) │ ├─ 创建 Phone 对象 (GsmCdmaPhone) │ ├─ 初始化 UiccController │ ├─ 启动 PhoneSubsystemService │ └─ 启动电话应用相关服务 │ └─ Phone 进程中的关键类: ├─ PhoneFactory (工厂类, 创建 Phone 对象) ├─ RIL (RIL 通信实现) ├─ Phone (电话对象基类) ├─ GsmCdmaPhone (具体实现) ├─ ServiceStateTracker (服务状态跟踪) └─ UiccController (SIM 卡控制器)
状态: 系统核心服务就绪, 可以进行网络操作
════════════════════════════════════════════════════════════════════════════════
【阶段 3】ConnectivityService 初始化 (~ 1-2 秒)
文件位置: • /packages_modules_Connectivity/service/src/com/android/server/ConnectivityService.java
3.1 ConnectivityService 创建流程
代码示例:
```java
// SystemServer.java - startOtherServices()
t.traceBegin("StartConnectivityService");
// This has to be called after NetworkManagementService, NetworkStatsService
// and NetworkPolicyManager
mSystemServiceManager.startServiceFromJar(
CONNECTIVITY_SERVICE_INITIALIZER_CLASS,
CONNECTIVITY_SERVICE_APEX_PATH
);
networkPolicy.bindConnectivityManager();
t.traceEnd();
```
3.2 ConnectivityService 构造函数初始化
├─ 初始化 Handler (ConnectivityServiceHandler)
├─ 初始化网络代理列表 (mNetAgentInfos)
├─ 初始化网络请求队列 (mNetworkRequests)
├─ 初始化 NetworkRanker (网络评分器)
├─ 初始化 Netd 连接 (INetd)
├─ 初始化 DNS 配置
├─ 初始化 VPN 管理
├─ 初始化权限监控 (PermissionMonitor)
├─ 注册广播接收者
│ ├─ ACTION_NET_RESTORE
│ ├─ ACTION_NET_RESET
│ ├─ ACTION_RESTRICT_BACKGROUND_CHANGED
│ └─ 其他系统广播
└─ 启动后台线程处理网络事件
3.3 ConnectivityService 关键数据结构
├─ Network 类: 代表单个网络对象
│ ├─ netHandle: 网络句柄
│ ├─ mNetworkAgentInfo: 关联的代理
│ └─ 用于 socket 绑定和网络操作
│
├─ NetworkCapabilities: 网络能力描述
│ ├─ 传输类型 (TRANSPORT_CELLULAR, TRANSPORT_WIFI 等)
│ ├─ 网络能力位
│ │ ├─ NET_CAPABILITY_INTERNET
│ │ ├─ NET_CAPABILITY_MMS
│ │ ├─ NET_CAPABILITY_NOT_METERED
│ │ └─ 其他能力
│ └─ 网络特性 (MTU, Signal Strength 等)
│
├─ NetworkRequest: 应用网络请求
│ ├─ requestId: 请求 ID
│ ├─ type: 请求类型 (REQUEST, LISTEN, TRACK_DEFAULT 等)
│ ├─ capabilities: 需要的能力
│ └─ specifier: 网络指定符
│
└─ NetworkAgentInfo: 网络代理信息
├─ mNetworkAgent: NetworkAgent 对象
├─ mNetwork: 代表的 Network
├─ mNetworkCapabilities: 网络能力
├─ mLinkProperties: 链接属性
├─ mScore: 网络评分
└─ mConnected: 连接状态
3.4 ConnectivityService 依赖关系
必须在以下服务之后启动:
├─ NetworkManagementService (网络管理底层接口)
├─ NetworkStatsService (网络统计服务)
├─ NetworkPolicyManager (网络策略管理)
├─ PhoneStateListener 注册 (来自 Telephony)
└─ PackageManager (获取应用权限)
状态: 网络管理框架就绪, 等待 NetworkAgent 注册
════════════════════════════════════════════════════════════════════════════════
【阶段 4】Phone 进程与 RIL 通信 (~ 2-3 秒)
4.1 RIL 连接建立
文件位置: • /frameworks_opt_telephony/src/java/com/android/internal/telephony/RIL.java
代码示例:
```java
// PhoneFactory.java
public static void makeDefaultPhones(Context context) {
makeDefaultPhone(context);
}
private static void makeDefaultPhone(Context context) {
synchronized (sLockProxyPhones) {
if (sPhone == null) {
// 创建 RIL 对象连接 rild
sRilConnections[i] = new RILProxy(context, i);
// 创建电话对象 (Phone)
sPhones[i] = new GsmCdmaPhone(
context,
sRilConnections[i], // RIL 连接
sPhoneNotifier,
i
);
}
}
}
```
4.2 RIL 初始化步骤
├─ 创建 RIL 对象并连接 rild (Radio Interface Layer daemon)
│ └─ rild 是一个 C 程序, 运行在 vendor 分区
│
├─ RIL 通过 socket 连接到 rild
│ └─ 通常路径: /dev/socket/rild
│
├─ 发送初始化命令到 rild:
│ ├─ RIL_REQUEST_GET_RADIO_CAPABILITY
│ ├─ RIL_REQUEST_GET_SIM_STATUS
│ ├─ RIL_REQUEST_RADIO_POWER (ON)
│ └─ RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
│
└─ rild 与 Modem(基带) 通信:
├─ 加载调制解调器固件
├─ 初始化调制解调器
├─ 启用射频模块
└─ 配置信号处理
4.3 Phone 对象创建
GsmCdmaPhone 初始化:
├─ 创建 ServiceStateTracker
│ └─ 跟踪服务状态 (IN_SERVICE/OUT_OF_SERVICE 等)
│
├─ 创建 UiccController
│ └─ 管理 SIM 卡 (UICC - Universal Integrated Circuit Card)
│
├─ 创建 ServiceStateTracker 事件处理器
│ ├─ EVENT_RADIO_STATE_CHANGED
│ ├─ EVENT_NETWORK_STATE_CHANGED
│ ├─ EVENT_GET_SIGNAL_STRENGTH
│ └─ 其他事件
│
└─ 注册事件监听:
├─ RadioStateListener
├─ PhoneStateListener
└─ NetworkStateListener
4.4 SIM 卡读取
代码流程:
├─ UiccController 查询 SIM 卡状态
├─ 发送命令到 rild: RIL_REQUEST_GET_SIM_STATUS
│
├─ rild 返回 SIM 状态:
│ ├─ CARD_ABSENT (卡不存在)
│ ├─ CARD_PRESENT (卡存在)
│ ├─ CARD_READY (卡就绪)
│ └─ CARD_ERROR (卡错误)
│
├─ 如果卡就绪, 读取 SIM 信息:
│ ├─ IMSI (International Mobile Subscriber Identity)
│ ├─ ICCID (Integrated Circuit Card ID)
│ ├─ 订阅信息
│ └─ 运营商配置
│
└─ 初始化订阅信息 (SubscriptionInfo)
4.5 网络搜索启动
ServiceStateTracker 开始搜索网络:
├─ 发送 RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE
├─ 发送 RIL_REQUEST_SET_NETWORK_SELECTION_MODE
│ └─ 设置为自动模式 (NETWORK_SELECTION_MODE_AUTO)
│
├─ 发送 RIL_REQUEST_QUERY_AVAILABLE_NETWORKS (可选)
│ └─ 扫描可用运营商
│
├─ 等待 URC (Unsolicited Result Code):
│ ├─ RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED
│ └─ RIL_UNSOL_VOICE_RADIO_TECH_CHANGED
│
└─ 更新 ServiceState:
├─ 设置运营商名称
├─ 设置运营商代码
├─ 设置漫游状态
└─ 更新信号强度
状态: RIL 就绪, 网络搜索开始, 等待网络注册
════════════════════════════════════════════════════════════════════════════════
【阶段 5】NetworkAgent 注册与网络连接 (~ 1-3 秒)
5.1 TelephonyNetworkFactory 创建与注册
文件位置: • /frameworks_opt_telephony/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java
代码流程:
├─ PhoneFactory 创建 TelephonyNetworkFactory
├─ TelephonyNetworkFactory 继承 NetworkProvider
├─ NetworkProvider 向 ConnectivityService 注册
│
└─ ConnectivityService 调用:
connectivityManager.registerNetworkProvider(this)
5.2 网络能力声明
TelephonyNetworkFactory 声明能力:
```java
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(TRANSPORT_CELLULAR);
// 添加蜂窝网络能力
mNetworkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
mNetworkCapabilities.addCapability(NET_CAPABILITY_MMS);
mNetworkCapabilities.addCapability(NET_CAPABILITY_SUPL);
mNetworkCapabilities.addCapability(NET_CAPABILITY_DUN);
mNetworkCapabilities.addCapability(NET_CAPABILITY_IMS);
mNetworkCapabilities.addCapability(NET_CAPABILITY_FOTA);
mNetworkCapabilities.addCapability(NET_CAPABILITY_CBS);
mNetworkCapabilities.addCapability(NET_CAPABILITY_IA);
mNetworkCapabilities.addCapability(NET_CAPABILITY_MMTEL);
// 设置链接下行能力
mNetworkCapabilities.setLinkDownstreamBandwidthKbps(12288); // 12 Mbps
```
5.3 NetworkAgent 创建与注册
步骤:
├─ 1. ServiceStateTracker 检测到网络注册成功
│ └─ EVENT_RADIO_ON
│ └─ EVENT_NETWORK_STATE_CHANGED
│
├─ 2. DataNetworkController 创建 NetworkAgent
│ ```java
│ mNetworkAgent = new NetworkAgent(
│ mContext,
│ mLooper,
│ "Cellular", // tag
│ mNetworkCapabilities,
│ mLinkProperties,
│ mNetworkScore,
│ mNetworkConfig
│ ) {
│ @Override
│ public void onNetworkRequested(NetworkRequest request) {
│ // 应用请求此网络
│ }
│
│ @Override
│ public void onNetworkUnwanted() {
│ // 网络不再需要
│ }
│ };
│ ```
│
├─ 3. NetworkAgent.register()
│ └─ 向 ConnectivityService 注册
│
├─ 4. ConnectivityService 处理注册:
│ ├─ 创建 NetworkAgentInfo
│ ├─ 添加到 mNetAgentInfos 列表
│ ├─ 评分网络 (NetworkRanker)
│ ├─ 选择默认网络
│ └─ 通知应用网络可用
│
└─ 5. 网络转换为 CONNECTING 状态
5.4 APN 配置
文件位置: • /frameworks_opt_telephony/src/java/com/android/internal/telephony/data/ApnContext.java
APN (Access Point Name) 配置步骤:
├─ 1. DataNetworkController 读取 APN 配置
│ ├─ 从 TelephonyProvider 读取
│ ├─ 默认 APN:
│ │ ├─ name: "Internet"
│ │ ├─ apn: "cmnet" (中国移动) / "uninet" (中国联通) 等
│ │ ├─ proxy: (代理地址, 可选)
│ │ ├─ port: (代理端口, 可选)
│ │ ├─ user: (用户名, 通常空)
│ │ ├─ password: (密码, 通常空)
│ │ ├─ mmsProxy: (MMS 代理)
│ │ ├─ mmsPort: (MMS 端口)
│ │ ├─ types: "default,supl,mms" (APN 类型)
│ │ └─ protocol: "IP" / "IPV6" / "IPV4V6"
│ │
│ └─ 特殊 APN:
│ ├─ MMS APN
│ ├─ SUPL APN
│ ├─ IMS APN
│ └─ DUN APN
│
├─ 2. 根据 APN 类型选择:
│ ├─ 默认数据: "default" APN
│ ├─ MMS: "mms" APN
│ ├─ SUPL: "supl" APN
│ └─ IMS: "ims" APN
│
└─ 3. 配置结果返回给 DataNetworkController
5.5 PS 附着 (Packet Switched Attach)
步骤:
├─ 1. ServiceStateTracker 检测到 CS 注册成功
│ └─ 网络类型: 2G, 3G, 4G (LTE), 5G (NR) 等
│
├─ 2. DataNetworkController 发起 PS 附着
│ └─ 发送命令: RIL_REQUEST_DATA_ATTACH
│ └─ 设置 PDP (Packet Data Protocol) 类型
│ └─ 设置 QoS (Quality of Service) 参数
│
├─ 3. Modem 执行 PS 附着
│ ├─ 向网络发送 Attach Request
│ ├─ 网络返回 Attach Accept
│ ├─ 分配 RAI (Routing Area Identification)
│ └─ Modem 状态变为 PS_ATTACHED
│
├─ 4. RIL 返回 PS 附着成功 URC:
│ └─ RIL_UNSOL_DATA_ATTACH_FAILED 或成功回调
│
└─ 5. ServiceState 更新为 PS 已附着
状态: 网络注册成功, PS 附着完成, 准备建立 DataCall
════════════════════════════════════════════════════════════════════════════════
【阶段 6】DataCall 建立与 IP 地址分配 (~ 0.5-2 秒)
6.1 DataConnection 创建与管理
步骤:
├─ 1. DataNetworkController 创建 DataConnection
│ └─ 针对每个 APN 类型创建独立的 DataConnection
│
├─ 2. 发送 setupDataCall 命令:
│ ```
│ RIL_REQUEST_SETUP_DATA_CALL
│ 参数:
│ - accessNetwork: 接入网类型 (UTRAN, EUTRAN, NGRAN 等)
│ - protocol: "IP" / "IPV6" / "IPV4V6"
│ - apn: APN 字符串 (如 "cmnet")
│ - username: 用户名 (通常空)
│ - password: 密码 (通常空)
│ - authType: 认证类型
│ - ipRoamingType: IP 漫游类型
│ - canHandleIms: 是否支持 IMS
│ ```
│
├─ 3. Modem 执行激活 PDP Context
│ ├─ 向网络发送 PDP Context Activate Request
│ ├─ 网络返回 PDP Context Activate Accept
│ ├─ 分配 PDP Address:
│ │ ├─ IPv4 地址 (如 10.10.10.10)
│ │ ├─ IPv6 前缀 (如 fe80::1/64)
│ │ ├─ 子网掩码
│ │ ├─ DNS 服务器地址
│ │ ├─ 网关地址
│ │ └─ MTU 大小
│ │
│ ├─ 配置 PDP Context:
│ │ ├─ QoS 参数
│ │ ├─ 传输类型 (如 PPP)
│ │ └─ 其他参数
│ │
│ └─ 返回成功回调
│
└─ 4. RIL 返回 setupDataCall 结果:
```
onSetupDataCallComplete:
{
serial: 请求序列号,
status: 0 (成功) 或错误码,
type: 数据连接类型,
ifname: 网络接口名 (如 "rmnet_data0"),
addresses: [
{
address: "10.10.10.10",
prefixLength: 32
}
],
dnses: ["8.8.8.8", "8.8.4.4"],
gateways: ["10.10.10.1"],
pcscfs: [],
mtu: 1500
}
```
6.2 网络接口配置
DataConnection 接收到回调后:
├─ 1. 提取网络接口名: "rmnet_data0"
│ └─ rmnet: "Radio Multiplexed Network"
│
├─ 2. 通过 Netd 配置网络接口:
│ ├─ 设置 IP 地址: "10.10.10.10/32"
│ ├─ 添加路由规则
│ ├─ 设置 DNS 服务器
│ ├─ 配置网络接口 MTU
│ └─ 启用网络接口
│
├─ 3. 更新 LinkProperties:
│ ```java
│ LinkProperties linkProperties = new LinkProperties();
│ linkProperties.setInterfaceName("rmnet_data0");
│ linkProperties.addLinkAddress(new LinkAddress("10.10.10.10/32"));
│ linkProperties.addDnsServer(InetAddress.getByName("8.8.8.8"));
│ linkProperties.setHttpProxy(null);
│ linkProperties.setMtu(1500);
│ ```
│
└─ 4. NetworkAgent.sendLinkProperties() 更新连接属性
6.3 NetworkAgent 状态转换
代码示例:
```java
// 1. 注册时状态: CONNECTING
mNetworkAgent.markConnecting();
// 2. IP 配置成功后: CONNECTED (但尚未验证)
mNetworkAgent.markConnected();
// 3. NetworkMonitor 验证网络后: VALIDATED
// (见阶段 7)
```
6.4 DataConnection 状态机
状态转换:
IDLE
↓
INITING (初始化)
↓
CONNECTING (连接中)
│ ├─ 发送 RIL_REQUEST_SETUP_DATA_CALL
│ └─ 等待回调
↓
CONNECTED (已连接)
│ ├─ IP 地址分配成功
│ ├─ 网络接口配置完成
│ └─ 等待网络验证
↓
VALIDATED (已验证, 可用)
│ └─ 应用可以正常使用网络
↓
DISCONNECTING (断开中)
↓
DISCONNECTED (已断开)
状态: DataCall 建立成功, 应用得到 IP 地址, 准备验证网络
════════════════════════════════════════════════════════════════════════════════
【阶段 7】网络验证与状态广播 (~ 2-10 秒)
7.1 NetworkMonitor 网络验证
文件位置: • /packages_modules_Connectivity/service/src/com/android/server/connectivity/NetworkMonitor.java
验证流程:
├─ 1. ConnectivityService 为新网络创建 NetworkMonitor
│
├─ 2. NetworkMonitor 执行多项验证测试:
│
│ ├─ DNS 测试:
│ │ ├─ 发送 DNS 查询: "www.google.com"
│ │ ├─ 预期获得 A 记录
│ │ └─ 超时时间: 5 秒
│ │
│ ├─ HTTP 测试:
│ │ ├─ 发送 HTTP GET 请求到: "http://www.google.com"
│ │ ├─ 预期收到: 204 No Content 或 200 OK
│ │ └─ 检查响应头中的 "captive-portal" 标记
│ │
│ ├─ HTTPS 测试:
│ │ ├─ 发送 HTTPS GET 请求到: "https://www.google.com"
│ │ ├─ 验证 SSL 证书
│ │ └─ 检查响应代码
│ │
│ ├─ Private DNS 测试 (DoH/DoT):
│ │ ├─ 测试私有 DNS 服务器连接
│ │ ├─ 尝试 DNS over TLS (DoT)
│ │ ├─ 尝试 DNS over HTTPS (DoH)
│ │ └─ 验证安全连接
│ │
│ └─ Captive Portal 检测:
│ ├─ 检查 HTTP 重定向
│ ├─ 检查 HTTPS 证书问题
│ ├─ 检查 Portal 登录页面
│ └─ 如果发现, 返回 PARTIAL 连接
│
└─ 3. 验证结果:
├─ VALID: 网络正常, 可以联网
├─ PARTIAL: 有限连接, 可能被 Captive Portal 拦截
└─ INVALID: 网络异常, 无网络
7.2 验证测试代码示例
```java
// NetworkMonitor.java
private int isCaptivePortal() {
// 1. DNS 测试
if (!testDns()) {
return NETWORK_TEST_RESULT_INVALID;
}
// 2. HTTP 测试
int httpCode = testHttpCode();
if (httpCode == 204 || httpCode == 200) {
// 网络正常
return NETWORK_VALIDATION_RESULT_VALID;
} else if (httpCode >= 300 && httpCode < 400) {
// 重定向, 可能是 Captive Portal
return NETWORK_VALIDATION_RESULT_PARTIAL;
}
// 3. HTTPS 测试
if (testHttps()) {
return NETWORK_VALIDATION_RESULT_VALID;
}
return NETWORK_VALIDATION_RESULT_INVALID;
}
```
7.3 标记网络为已验证
```java
// NetworkMonitor 完成验证后
if (validationResult == NETWORK_VALIDATION_RESULT_VALID) {
// 通过 INetworkMonitorCallbacks 通知 ConnectivityService
mCallback.notifyNetworkTested(
NETWORK_VALIDATION_RESULT_VALID,
null
);
}
// ConnectivityService 处理验证结果
// mNetworkAgent.markValidated();
```
7.4 网络状态广播
ConnectivityService 发送广播通知应用:
├─ ACTION_CONNECTIVITY_CHANGE
│ └─ 已弃用 (deprecated), 应使用 ConnectivityManager.NetworkCallback
│
├─ ConnectivityManager.NetworkCallback 回调:
│ ├─ onAvailable(Network network)
│ │ └─ 网络可用 (仅 CONNECTED, 不一定 VALIDATED)
│ │
│ ├─ onCapabilitiesChanged(Network network, NetworkCapabilities capabilities)
│ │ └─ 网络能力改变
│ │
│ ├─ onLinkPropertiesChanged(Network network, LinkProperties linkProperties)
│ │ └─ 链接属性改变 (IP地址、DNS 等)
│ │
│ ├─ onNetworkCapabilitiesChanged(Network network, NetworkCapabilities capabilities)
│ │ └─ 网络能力改变 (VALIDATED 状态改变时)
│ │
│ └─ onLost(Network network)
│ └─ 网络连接丢失
│
└─ 代码示例:
```java
// 应用代码
connectivityManager.registerNetworkCallback(request, new NetworkCallback() {
@Override
public void onAvailable(Network network) {
Log.d(TAG, "Network available: " + network);
// 网络可用, 但可能尚未验证
// 应用可以开始使用网络
}
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities capabilities) {
if (capabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
Log.d(TAG, "Network validated");
// 网络已验证, 通常现在才能正常访问互联网
}
}
@Override
public void onLost(Network network) {
Log.d(TAG, "Network lost: " + network);
// 网络连接丢失
}
});
```
7.5 网络选择与切换
ConnectivityService 的网络评分与选择:
├─ 1. NetworkRanker 对所有可用网络评分
│ ├─ 评分因素:
│ │ ├─ 网络类型 (5G > 4G > 3G > 2G, WiFi 通常最优)
│ │ ├─ 信号强度
│ │ ├─ 网络负载 (拥塞程度)
│ │ ├─ 延迟 (RTT)
│ │ ├─ 用户偏好
│ │ └─ 功耗
│ │
│ └─ 得分: 0-100+ 分
│
├─ 2. 选择最高分的网络作为默认网络
│ └─ 更新 mDefaultNetwork
│
├─ 3. 通知应用网络已改变
│ └─ 发送 ConnectivityManager.NetworkCallback 回调
│
└─ 4. 如果需要, 断开旧的默认网络
└─ 设置超时时间, 一段时间后断开
状态: 网络已验证, 应用收到网络可用通知, 可以正常上网
════════════════════════════════════════════════════════════════════════════════
【完整时间线总结】
事件 时间 累积时间 ────────────────────────────────────────────────────
- 手机开机 0 秒 0 秒
- 内核启动 1-2 秒 1-2 秒
- Init 进程启动 0.5-1 秒 1.5-3 秒
- Zygote 启动 0.5-1 秒 2-4 秒
- SystemServer 启动 1-2 秒 3-6 秒
- Phone 进程启动 0.5-1 秒 3.5-7 秒
- RIL 初始化 0.5-1 秒 4-8 秒
- SIM 卡读取 0.5-1 秒 4.5-9 秒
- 网络搜索 5-20 秒 9.5-29 秒
- 网络注册成功 0.5-1 秒 10-30 秒
- NetworkAgent 注册 0.5-1 秒 10.5-31 秒
- PS 附着 0.5-1 秒 11-32 秒
- DataCall 建立 1-2 秒 12-34 秒
- IP 地址获取 0.5-1 秒 12.5-35 秒
- 网络验证 2-10 秒 14.5-45 秒
- 广播网络可用 0.5-1 秒 15-46 秒 ──────────────────────────────────────────────────── 总计: 15-46 秒 (取决于信号强度、运营商配置等)
════════════════════════════════════════════════════════════════════════════════
【关键类与方法速查】
SystemServer.java: ├─ startBootstrapServices() - 启动引导服务 ├─ startCoreServices() - 启动核心服务 └─ startOtherServices() - 启动其他服务 (包括 ConnectivityService)
PhoneFactory.java: ├─ makeDefaultPhones() - 创建默认 Phone 对象 └─ makeDefaultPhone() - 创建单个 Phone 对象
ConnectivityService.java: ├─ ConnectivityService() - 构造函数, 初始化 ├─ systemReady() - 系统就绪 ├─ handleNetworkAgentDisconnected() - 处理网络代理断开 ├─ updateNetworks() - 更新网络列表 └─ selectBestNetwork() - 选择最佳网络
NetworkAgent.java: ├─ register() - 向 ConnectivityService 注册 ├─ sendNetworkCapabilities() - 发送网络能力 ├─ sendLinkProperties() - 发送链接属性 ├─ markConnecting() - 标记为连接中 ├─ markConnected() - 标记为已连接 └─ markValidated() - 标记为已验证
Phone.java: ├─ Phone() - 构造函数 ├─ handleMessage() - 处理消息 └─ getServiceState() - 获取服务状态
ServiceStateTracker.java: ├─ onSignalStrengthResult() - 处理信号强度 ├─ pollState() - 轮询网络状态 └─ handleNetworkStateChanged() - 处理网络状态改变
DataConnection (及其衍生类): ├─ bringUp() - 建立数据连接 ├─ bringDown() - 断开数据连接 ├─ setupDataCall() - 设置数据连接 └─ handleSetupDataCallComplete() - 处理设置完成回调
════════════════════════════════════════════════════════════════════════════════
【关键 Intent 和广播】
系统广播: ├─ Intent.ACTION_BOOT_COMPLETED - 手机启动完成 ├─ TelephonyManager.ACTION_PHONE_STATE_CHANGED - 电话状态改变 ├─ Intent.ACTION_SIGNAL_STRENGTH_CHANGED - 信号强度改变 ├─ TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED - 数据连接状态改变 └─ Intent.ACTION_AIRPLANE_MODE_CHANGED - 飞行模式切换
ConnectivityManager 回调: ├─ NetworkCallback.onAvailable() - 网络可用 ├─ NetworkCallback.onCapabilitiesChanged() - 网络能力改变 ├─ NetworkCallback.onLinkPropertiesChanged() - 链接属性改变 └─ NetworkCallback.onLost() - 网络丢失
════════════════════════════════════════════════════════════════════════════════
【性能优化建议】
-
加快启动时间: ├─ 减少 RIL 初始化命令数量 ├─ 并行执行可并行的初始化任务 ├─ 优化网络搜索算法 └─ 缓存已知运营商信息
-
改进用户体验: ├─ 提供启动进度指示 ├─ 优先启动常用网络 (WiFi) ├─ 加快网络验证 └─ 处理多网络场景
-
电源管理: ├─ 关闭不需要的功能 ├─ 优化 RIL 休眠策略 ├─ 使用低功耗网络优先 └─ 智能网络预连接
════════════════════════════════════════════════════════════════════════════════