目录
[1.1 需求场景](#1.1 需求场景)
[1.2 技术选型分析](#1.2 技术选型分析)
[1.3 涉及的关键类](#1.3 涉及的关键类)
[2.1 源码定位](#2.1 源码定位)
[2.2 实现思路](#2.2 实现思路)
[2.3 代码实现](#2.3 代码实现)
[2.4 关键技术要点](#2.4 关键技术要点)
前言
在嵌入式 Android 设备开发中,经常遇到这样的场景:设备作为无线接入点(AP)使用,需要开机后自动开启共享热点,以便其他设备能够快速连接并进行通信。例如智能家居网关、工业数据采集器、车载娱乐系统等,都需要设备在开机后立即可被发现和连接。
本文将基于 RK3568 平台的 Android 13 SDK,详细介绍如何通过修改 Framework 层代码,实现开机检测 WiFi 状态,在 WiFi 未开启时自动开启共享热点,并设置指定的热点名称和密码。
一、基本介绍
1.1 需求场景
有一台基于 RK3568 的 Android 设备,需要满足以下需求:
-
开机自启动:设备启动完成后自动执行检测逻辑
-
状态检测:检测 WiFi 开关是否已经打开
-
智能决策:如果 WiFi 未打开,则自动开启共享热点
-
固定配置:热点名称为 BoxControl,密码为 13572468
1.2 技术选型分析
在 Android 系统中,实现开机自动执行任务有几种常见方式:
| 方案 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| Shell 脚本 | 通过 init.rc 执行脚本 | 快速实现,无需编译系统 | 权限受限,配置热点困难 |
| 系统 App | 开发 APK 监听开机广播 | 灵活可迭代 | 需要系统签名,启动时序晚 |
| Framework 修改 | 修改 WifiServiceImpl | 最稳定可靠,深度集成 | 需要编译整个系统 |
考虑到热点配置需要在系统服务层面完成,且需要稳定的启动时序,修改 Framework 层代码是最佳选择。
1.3 涉及的关键类
-
WifiServiceImpl:WiFi 核心服务类,管理所有 WiFi 相关操作 -
SoftApConfiguration:热点配置类,包含 SSID、密码、安全类型等 -
WifiApConfigStore:热点配置存储类,负责配置的持久化 -
ActiveModeWarden:模式管理器,负责 WiFi 和热点的模式切换
二、具体实施
2.1 源码定位
RK3568 Android 13 SDK 中,WiFi 服务源码位于:
bash
packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
2.2 实现思路
整个实现分为三个关键步骤:
-
在服务启动入口添加调用 :在
checkAndStartWifi()方法中插入自定义逻辑 -
实现核心检测方法:检查 WiFi 状态,构建并保存热点配置
-
启动热点:调用系统 API 开启共享热点
2.3 代码实现
第一步:在 checkAndStartWifi() 中添加调用
java
public void checkAndStartWifi() {
mWifiThreadRunner.post(() -> {
// ... 原有初始化代码 ...
mActiveModeWarden.start();
registerForCarrierConfigChange();
mWifiInjector.getAdaptiveConnectivityEnabledSettingObserver().initialize();
// 开机自动启动热点
checkAndStartHotspotIfWifiOff();
mIsWifiServiceStarted = true;
});
}
第二步:实现核心检测方法
java
/**
* 检查WiFi状态,如果WiFi未开启则自动启动热点
*/
private void checkAndStartHotspotIfWifiOff() {
final String HOTSPOT_SSID = "BoxControl";
final String HOTSPOT_PASSWORD = "13572468";
// 延迟5秒执行,等待系统服务完全初始化
mWifiThreadRunner.postDelayed(() -> {
try {
// 1. 检查WiFi是否开启
int wifiState = mActiveModeWarden.getWifiState();
boolean isWifiEnabled = (wifiState == WIFI_STATE_ENABLED);
if (!isWifiEnabled) {
// 2. 检查热点是否已开启
int apState = mTetheredSoftApTracker.getState();
if (apState == WIFI_AP_STATE_ENABLED) {
Log.w(TAG, "Hotspot already enabled, skip auto-start");
return;
}
// 3. 检查用户限制
if (mWifiTetheringDisallowed) {
Log.w(TAG, "Tethering is disallowed by user restriction");
return;
}
// 4. 构建热点配置
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
.setSsid(HOTSPOT_SSID)
.setPassphrase(HOTSPOT_PASSWORD,
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
.build();
// 5. 保存配置
mWifiApConfigStore.setApConfiguration(softApConfig);
Log.i(TAG, "Hotspot configuration saved: SSID=" + HOTSPOT_SSID);
// 6. 启动热点
boolean started = startTetheredHotspot(null, "android");
if (!started) {
// 备选方案:直接调用内部方法
WorkSource requestorWs = new WorkSource(Process.SYSTEM_UID, "android");
SoftApCapability capability = mTetheredSoftApTracker.getSoftApCapability();
SoftApModeConfiguration apConfig = new SoftApModeConfiguration(
WifiManager.IFACE_IP_MODE_TETHERED,
softApConfig,
capability);
startSoftApInternal(apConfig, requestorWs);
}
}
} catch (Exception e) {
Log.e(TAG, "Error in auto-start hotspot", e);
}
}, 5000);
}
2.4 关键技术要点
关于延迟执行
使用 postDelayed(5000) 延迟 5 秒执行,原因如下:
-
WiFi 服务在
checkAndStartWifi()中初始化,但底层驱动和 HAL 层需要时间准备 -
热点启动依赖
WifiApConfigStore等组件就绪 -
适当延迟可避免时序竞争导致的启动失败
关于配置保存
先调用 mWifiApConfigStore.setApConfiguration(softApConfig) 保存配置,再启动热点。这是因为 startTetheredHotspot(null, "android") 会从 WifiApConfigStore 读取配置,如果不先保存,可能使用旧配置。
关于双方案保障
代码中实现了主备两套启动方案:
-
主方案 :
startTetheredHotspot(null, "android")- 标准 API -
备选方案 :
startSoftApInternal()- 内部方法,绕过部分权限检查
总结
本文介绍了在 RK3568 Android 13 SDK 中,通过修改 WifiServiceImpl.java 实现开机自动开启共享热点的方法。希望本文对从事 Android 系统开发的同行们有所帮助。