手机从开机到上网的关键步骤

0 阅读14分钟

手机从开机到上网的关键步骤,包括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
│      ```javamNetworkAgent = 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. 如果需要, 断开旧的默认网络
     └─ 设置超时时间, 一段时间后断开

状态: 网络已验证, 应用收到网络可用通知, 可以正常上网

════════════════════════════════════════════════════════════════════════════════

【完整时间线总结】

事件 时间 累积时间 ────────────────────────────────────────────────────

  1. 手机开机 0 秒 0 秒
  2. 内核启动 1-2 秒 1-2 秒
  3. Init 进程启动 0.5-1 秒 1.5-3 秒
  4. Zygote 启动 0.5-1 秒 2-4 秒
  5. SystemServer 启动 1-2 秒 3-6 秒
  6. Phone 进程启动 0.5-1 秒 3.5-7 秒
  7. RIL 初始化 0.5-1 秒 4-8 秒
  8. SIM 卡读取 0.5-1 秒 4.5-9 秒
  9. 网络搜索 5-20 秒 9.5-29 秒
  10. 网络注册成功 0.5-1 秒 10-30 秒
  11. NetworkAgent 注册 0.5-1 秒 10.5-31 秒
  12. PS 附着 0.5-1 秒 11-32 秒
  13. DataCall 建立 1-2 秒 12-34 秒
  14. IP 地址获取 0.5-1 秒 12.5-35 秒
  15. 网络验证 2-10 秒 14.5-45 秒
  16. 广播网络可用 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() - 网络丢失

════════════════════════════════════════════════════════════════════════════════

【性能优化建议】

  1. 加快启动时间: ├─ 减少 RIL 初始化命令数量 ├─ 并行执行可并行的初始化任务 ├─ 优化网络搜索算法 └─ 缓存已知运营商信息

  2. 改进用户体验: ├─ 提供启动进度指示 ├─ 优先启动常用网络 (WiFi) ├─ 加快网络验证 └─ 处理多网络场景

  3. 电源管理: ├─ 关闭不需要的功能 ├─ 优化 RIL 休眠策略 ├─ 使用低功耗网络优先 └─ 智能网络预连接

════════════════════════════════════════════════════════════════════════════════