移动数据始终开启功能

10 阅读4分钟

1. 功能定义和原理

移动数据始终开启是一个系统设置,它允许移动数据连接在 WiFi 等高优先级网络活跃时继续保持连接和活跃

工作模式:

关闭始终开启:
WiFi 连接 → 移动数据自动断开 ✗
    
开启始终开启:
WiFi 连接 + 移动数据 → 都保持连接 ✓

优势:

  • 更快的网络切换(两个网络都活跃)
  • 应用可以在 WiFi 和移动数据间灵活切换
  • 降低网络延迟和中断

2. 设置存储 (ConnectivitySettingsManager)

// 常量定义
public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";

// 读取设置
public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
    final int enable = Settings.Global.getInt(
            context.getContentResolver(), 
            MOBILE_DATA_ALWAYS_ON,      // 全局设置键
            (def ? 1 : 0));              // 默认值
    return (enable != 0) ? true : false;
}

// 写入设置
public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
    Settings.Global.putInt(
            context.getContentResolver(), 
            MOBILE_DATA_ALWAYS_ON, 
            (enable ? 1 : 0));           // 1 = 开启,0 = 关闭
}

存储位置:

  • 数据库:Settings.Global(系统全局设置)
  • 键:mobile_data_always_on
  • 值:0 (关闭) 或 1 (开启)

3. 连接服务实现 (ConnectivityService)

核心组件

// 移动数据的"始终开启"网络请求
private final NetworkRequest mDefaultMobileDataRequest;

// 该请求的信息
// 当设置为开启时,这个请求始终存在
// 当设置为关闭时,这个请求被撤销

初始化流程

// 创建移动数据的始终开启请求
mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
        NetworkCapabilities.TRANSPORT_CELLULAR,    // 仅 4G/5G
        NetworkRequest.Type.BACKGROUND_REQUEST);   // 后台请求

// 在系统就绪时配置
onSystemReady() {
    // ...
    // 根据设置创建网络请求
    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
}

设置监听

private void registerSettingsCallbacks() {
    // 监听 MOBILE_DATA_ALWAYS_ON 设置变更
    mSettingsObserver.observe(
            Settings.Global.getUriFor(
                ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON),
            EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);  // 触发重新配置
    
    // 监听 WiFi 始终请求设置
    mSettingsObserver.observe(
            Settings.Global.getUriFor(
                ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
            EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
}

4. 动态配置机制

配置处理 (handleConfigureAlwaysOnNetworks)

Setting 改变
        ↓
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS
        ↓
handleConfigureAlwaysOnNetworks()
        ├─ 检查 MOBILE_DATA_ALWAYS_ON 设置值
        ├─ 检查 WIFI_ALWAYS_REQUESTED 设置值
        └─ 检查 config_vehicleInternalNetworkAlwaysRequested 配置值

核心代码:

private void handleConfigureAlwaysOnNetworks() {
    // 处理移动数据始终开启
    handleAlwaysOnNetworkRequest(
            mDefaultMobileDataRequest,
            ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON, 
            true /* defaultValue */);      // 默认开启
    
    // 处理 WiFi 始终请求
    handleAlwaysOnNetworkRequest(
            mDefaultWifiRequest,
            ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED,
            false /* defaultValue */);     // 默认关闭
    
    // 处理车辆内部网络
    final boolean vehicleAlwaysRequested = mResources.get().getBoolean(
            R.bool.config_vehicleInternalNetworkAlwaysRequested);
    handleAlwaysOnNetworkRequest(mDefaultVehicleRequest, vehicleAlwaysRequested);
}

5. 网络请求管理

启用始终开启 (设置 ON)

private void handleAlwaysOnNetworkRequest(
        NetworkRequest networkRequest, 
        boolean enable) {
    
    // 检查请求是否已存在
    final boolean isEnabled = (mNetworkRequests.get(networkRequest) != null);
    
    // 如果状态已匹配,无需操作
    if (enable == isEnabled) {
        return;
    }
    
    // 启用:注册网络请求
    if (enable) {
        handleRegisterNetworkRequest(new NetworkRequestInfo(
                Process.myUid(),
                networkRequest,
                null /* messenger */,
                null /* binder */,
                NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
                null /* attributionTags */));
    } 
    // 禁用:释放网络请求
    else {
        handleReleaseNetworkRequest(
                networkRequest, 
                Process.SYSTEM_UID,
                false /* callOnUnavailable */);
    }
}

6. 完整执行流程

用户打开设置
        ↓
更改 MOBILE_DATA_ALWAYS_ON 为 ON
        ↓
调用 ConnectivitySettingsManager.setMobileDataAlwaysOn()
        ↓
Settings.Global 数据库更新
        ↓
ContentObserver 检测到变更
        ↓
发送 EVENT_CONFIGURE_ALWAYS_ON_NETWORKS
        ↓
handleConfigureAlwaysOnNetworks()
        ↓
handleAlwaysOnNetworkRequest(mDefaultMobileDataRequest, true)
        ↓
handleRegisterNetworkRequest()
        ↓
在网络管理中注册 "CELLULAR + INTERNET" 请求
        ↓
ConnectivityService 确保移动数据网络始终活跃
        ↓
即使 WiFi 连接,移动数据仍保持活跃 ✓

7. 网络请求类型详解

mDefaultMobileDataRequest 的特性

// 创建始终开启请求
private NetworkRequest createDefaultInternetRequestForTransport(
        int transportType, 
        NetworkRequest.Type type) {
    
    final NetworkCapabilities netCap = new NetworkCapabilities();
    netCap.clearAll();
    netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
    netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);  // 仅移动数据
    netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
    
    return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
}

// 网络请求特性:
// - 类型:BACKGROUND_REQUEST(后台请求)
// - 优先级:低(不会抢占用户请求)
// - 持久性:始终存在(当设置开启时)
// - 作用:保持移动数据网络连接

8. 与其他功能的关系

移动数据始终开启
        │
        ├─ WiFi 始终请求 (WIFI_ALWAYS_REQUESTED)
        │   ├─ 类似机制,用于 WiFi 网络
        │   └─ 优先级:WiFi > 移动数据
        │
        ├─ 网络请求 (NetworkRequest)
        │   ├─ 应用可以发起自己的网络请求
        │   └─ 系统基于优先级选择最优网络
        │
        └─ 网络切换 (Network Switching)
            ├─ 两个网络都活跃时更快切换
            └─ 应用可以在 WiFi/移动数据间灵活选择

9. 实际工作流程图

网络状态变化时序:

事件 1:只有移动数据连接
移动数据活跃 → 应用使用移动数据 ✓

事件 2WiFi 连接上
│
├─ 移动数据始终开启 = OFF
│   → 移动数据断开 ✗
│   → 应用切换到 WiFi ✓
│   → 网络切换延迟较大
│
└─ 移动数据始终开启 = ON
    → 移动数据保持连接 ✓
    → WiFi 也连接 ✓
    → 应用可瞬间在两网间切换 ✓
    → 网络切换延迟极小

事件 3WiFi 断开
│
├─ 移动数据始终开启 = OFF
│   → 移动数据已断开,需重新连接
│   → 恢复延迟:1-3 秒
│
└─ 移动数据始终开启 = ON
    → 移动数据已保持连接
    → 恢复延迟:几毫秒 ✓

10. 性能和电池影响

设置状态电池消耗网络延迟使用场景
关闭⬇️ 低⬆️ 高(需重连)省电,偶尔使用
开启⬆️ 中等⬇️ 低(已连接)实时应用,视频通话

电池消耗主要来自:

  • 保持无线电活跃
  • 定期信号强度查询
  • 网络数据包保活

总结

移动数据始终开启是一个智能网络管理功能:

  1. 存储层:全局设置 MOBILE_DATA_ALWAYS_ON
  2. 监听层:ContentObserver 监测设置变更
  3. 请求层:通过 NetworkRequest 机制向 ConnectivityService 注册请求
  4. 执行层:ConnectivityService 确保移动网络始终活跃
  5. 结果:WiFi 和移动数据可同时连接,应用可无缝切换

这个设计体现了 Android 系统模块化、事件驱动的架构特点。