📌一、系统启动阶段:WiFi 服务在 system_server 进程中

的初始化

android/frameworks/base/services/java/com/android/server/SystemServer.java中,系统会检查设备是否支持 WiFi 功能(通过PackageManager.FEATURE_WIFI判断)。若支持,则通过mSystemServiceManager.startServiceFromJar启动两个核心服务:

  • WifiService(主服务,负责 WiFi 核心功能调度)
  • WifiScanningService(扫描服务,专门处理 WiFi 扫描逻辑)
    代码片段如下:
private static final String WIFI_SERVICE_CLASS =
		"com.android.server.wifi.WifiService";

if (context.getPackageManager().hasSystemFeature(
		PackageManager.FEATURE_WIFI)) {
    // 优先启动WiFi主服务,为依赖组件提供基础
    t.traceBegin("StartWifi");
    mSystemServiceManager.startServiceFromJar(
        WIFI_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
    t.traceEnd();
    // 启动扫描服务,处理WiFi扫描相关任务
    t.traceBegin("StartWifiScanning");
    mSystemServiceManager.startServiceFromJar(
        WIFI_SCANNING_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
    t.traceEnd();
}

📌二、服务注册机制:将 WiFi 服务暴露给系统

WifiService启动后,需通过publishBinderService方法注册到ServiceManager,使其他组件可通过 Binder 机制调用其功能。该方法定义于android/frameworks/base/services/core/java/com/android/server/SystemService.java

/**
 * 发布服务,使其可被其他服务和应用访问
 * @param name 服务名称(如WiFi服务对应Context.WIFI_SERVICE)
 * @param service Binder服务实例(此处为WifiServiceImpl)
 * @param allowIsolated 是否允许隔离进程访问
 * @param dumpPriority 支持的dump优先级掩码
 */
protected final void publishBinderService(String name, IBinder service,
    boolean allowIsolated, int dumpPriority) {
    ServiceManager.addService(name, service, allowIsolated, dumpPriority);
}

📌三、WifiService 与 WifiServiceImpl 的职责划分

WifiService是系统服务入口,而WifiServiceImpl是实际业务逻辑的执行者,二者通过组合模式协作:

  1. WifiService 的初始化
    android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiService.java
public WifiService(Context contextBase) {
    super(contextBase);
    mWifiContext = new WifiContext(contextBase); // 创建WiFi专用上下文
    WifiInjector injector = new WifiInjector(mWifiContext); // 依赖注入器,管理WiFi组件
    WifiAsyncChannel channel = new WifiAsyncChannel(TAG); // 异步通信通道
    // 初始化核心实现类WifiServiceImpl
    mImpl = new WifiServiceImpl(mWifiContext, injector, channel);
}
  1. 服务注册触发
    WifiServiceonStart阶段调用publishBinderService,将WifiServiceImpl实例注册到系统:
@Override
public void onStart() {
    Log.i(TAG, "Registering " + Context.WIFI_SERVICE);
    publishBinderService(Context.WIFI_SERVICE, mImpl); // 注册核心实现类
}

核心区别

  • WifiService:系统服务的 “壳”,负责启动流程和服务注册,不处理具体业务。
  • WifiServiceImpl:WiFi 服务的 “大脑”,接收并处理所有应用层请求(如开关 WiFi、扫描、连接网络等)。

📌四、WifiServiceImpl 的初始化与核心依赖

WifiServiceImpl在构造时通过WifiInjector获取关键组件,奠定 WiFi 功能基础android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

public WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel) {
    mContext = context;
    mWifiInjector = wifiInjector; // 依赖注入器,提供组件实例
    ...
    // 客户端模式管理器:负责STA(Station)模式下的连接管理
    mClientModeImpl = mWifiInjector.getClientModeImpl();
    // 活跃模式控制器:管理WiFi的多种工作模式(如STA、AP、P2P等)
    mActiveModeWarden = mWifiInjector.getActiveModeWarden();
    ...
}

关键组件作用

  • WifiInjector:依赖注入工具,统一管理 WiFi 模块的对象创建和依赖关系,降低组件耦合。
  • WifiAsyncChannel:异步通信工具,用于跨进程 / 线程的消息传递(如与 WiFi 芯片驱动交互)。
  • ClientModeImpl:处理 STA 模式(设备作为客户端连接其他 WiFi)的核心逻辑。
  • ActiveModeWarden:协调 WiFi 的多种工作模式(如同时开启 STA 和热点时的资源分配)。

📌五、点击 WiFi 开关后的事件流转(从 UI 到服务层)

当用户在设置界面点击 WiFi 开关,系统通过 WifiManager.setWifiEnabled(boolean) 接口触发 WiFi 状态变更。该调用通过 AIDL 机制传递至 WifiServiceImpl,并在其中完成权限校验与状态切换:
android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

@Override
public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
    // 权限校验:是否具备修改 WiFi 状态的权限
    if (enforceChangePermission(packageName) != MODE_ALLOWED) return false;
    boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());

    // 非特权应用的限制条件
    if (!isPrivileged && !isDeviceOrProfileOwner(...) && !mWifiPermissionsUtil.isTargetSdkLessThan(...) && !isSystem(...)) {
        mLog.info("setWifiEnabled not allowed for uid=%").c(Binder.getCallingUid()).flush();
        return false;
    }

    // 飞行模式下限制 WiFi 开关
    if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
        mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
        return false;
    }

    // 热点开启时限制 WiFi 开关
    if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
        mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
        return false;
    }

    // 日志记录与状态处理
    mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName).c(Binder.getCallingUid()).c(enable).flush();
    long ident = Binder.clearCallingIdentity();
    try {
        if (!mSettingsStore.handleWifiToggled(enable)) return true;
    } finally {
        Binder.restoreCallingIdentity(ident);
    }

    // 记录用户行为指标
    if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) {
        if (enable) {
            mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON);
        } else {
            WifiInfo wifiInfo = mClientModeImpl.syncRequestConnectionInfo();
            mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF,
                wifiInfo == null ? -1 : wifiInfo.getNetworkId());
        }
    }

    mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);

    // 通知状态机:WiFi 开关已触发
    mActiveModeWarden.wifiToggled();
    return true;
}

小结

  • 权限控制非常严格,确保只有系统级或特权应用能在特定状态下切换 WiFi。
  • 状态变更最终通过 ActiveModeWarden.wifiToggled() 进入 WiFi 状态机流程。

📌六、ActiveModeWarden 与 WiFi 状态机的联动机制

ActiveModeWarden 是 WiFi 模式调度的核心组件,负责协调 STA(客户端)、SoftAP(热点)、P2P 等模式的切换。其 wifiToggled() 方法是 WiFi 状态变更的入口:

//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
public void wifiToggled() {
    mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED);
}
  1. 状态机初始化流程
    WifiServiceImpl有下面三个状态:

    WifiServiceImpl 启动阶段,ActiveModeWarden.start() 会根据当前设置初始化状态机:
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
public void start() {
    if (shouldEnableSta()) {
        startClientModeManager();
        setInitialState(mEnabledState);
    } else {
        setInitialState(mDisabledState);
    }
}

private boolean shouldEnableSta() {
    return mSettingsStore.isWifiToggleEnabled() || checkScanOnlyModeAvailable();
}
  • 若 WiFi 开关为开启或允许扫描模式,则进入 mEnabledState
  • 否则进入 mDisabledState,等待用户触发。
  1. CMD_WIFI_TOGGLED 消息处理逻辑
    当状态机处于 mDisabledState 且收到 CMD_WIFI_TOGGLED 消息时,会尝试启动 STA 模式:
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
case CMD_WIFI_TOGGLED:
    if (shouldEnableSta()) {
        startClientModeManager();
        transitionTo(mEnabledState);
    }
    break;
  1. 启动 ClientModeManager
    startClientModeManager() 方法创建并启动 STA 模式管理器:
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
private boolean startClientModeManager() {
    ClientListener listener = new ClientListener();
    ClientModeManager manager = mWifiInjector.makeClientModeManager(listener);
    listener.setActiveModeManager(manager);
    manager.start();

    if (!switchClientModeManagerRole(manager)) return false;

    mActiveModeManagers.add(manager);
    return true;
}

组件说明

  • ClientModeManager:负责 STA 模式的生命周期管理。
  • ClientListener:监听器,用于接收状态变更回调。
  • switchClientModeManagerRole():切换角色(如主连接 vs 辅助连接)。

📌七、WifiController 状态机响应 WiFi 开关事件

ActiveModeWarden 决定启动 STA(Station)模式后,会执行 startClientModeManager(),核心动作是创建 ClientModeManager 实例,并开始切换到对应角色(如 ROLE_CLIENT_PRIMARYROLE_CLIENT_SCAN_ONLY)。

  1. ClientModeManager 创建时,初始化自己的内部状态机
    在构造函数中会创建一个 ClientModeStateMachine,用于管理 WiFi 客户端模式的生命周期
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
ClientModeManager(...) {
     ...
    mStateMachine = new ClientModeStateMachine(looper);
	mDeferStopHandler = new DeferStopHandler(TAG, looper);
	...
}
  1. start() → 设置默认角色为 “扫描模式” + 启动状态机
    ClientModeManager 的 start() 方法会先设置目标模式为扫描-only,然后把 CMD_START 发送到状态机
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
public void start() {
     mTargetRole = ROLE_CLIENT_SCAN_ONLY;  // 默认只是扫描模式
     mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
}

此时,仅启动了状态机,还没有真正进入“连接热点”的模式。

  1. ClientModeStateMachine 的状态结构 & 初始状态
    ClientModeStateMachine 内部定义了 4 个状态:
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
ClientModeStateMachine(Looper looper) {
    addState(mIdleState);
	addState(mStartedState);
	addState(mScanOnlyModeState, mStartedState);
	addState(mConnectModeState, mStartedState);
	setInitialState(mIdleState);
	start();   // 启动状态机
	}

状态解释

  • mIdleState:WiFi 功能未启动
  • mStartedState:已进入 Client 模式,但不确定是 Scan-only 还是 Connect
  • mScanOnlyModeState:仅用于扫描,不允许连接 AP
  • mConnectModeState:设备可以开始连接 WiFi AP(真正 STA 模式)
  1. ActiveModeWarden 调用 switchClientModeManagerRole() 触发角色切换
    当 WiFi 开关打开时,ActiveModeWarden 会判断是扫描-only还是真正连接模式,并调用 setRole() 推动状态机切换角色
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
private boolean switchClientModeManagerRole(ClientModeManager modeManager) {
    if (mSettingsStore.isWifiToggleEnabled()) {
        modeManager.setRole(ROLE_CLIENT_PRIMARY); // 打开 WiFi → STA 模式
    } else if (checkScanOnlyModeAvailable()) {
        modeManager.setRole(ROLE_CLIENT_SCAN_ONLY);
    }
}

  1. setRole() 发送消息给状态机执行模式切换
//android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeManager.java
public void setRole(@Role int role) {
	Preconditions.checkState(CLIENT_ROLES.contains(role));
	if (role == ROLE_CLIENT_SCAN_ONLY) {
		mTargetRole = role;
		// Switch client mode manager to scan only mode.
		mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE);
	} else if (CLIENT_CONNECTIVITY_ROLES.contains(role)) {
		mTargetRole = role;
		// Switch client mode manager to connect mode.
		mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE, role);
	}
}

当收到 CMD_SWITCH_TO_CONNECT_MODE 时,状态机会从 ScanOnlyModeIdle 切入 ConnectModeState,真正启动 STA 连接流程。

  1. 小结
    ActiveModeWarden 负责“决定模式”,ClientModeManager 负责“执行模式”,ClientModeStateMachine 负责“把模式跑起来”。
    到这里 WiFiController 状态机完成 Disabled → Enabled 状态跳转,WiFiController 在 DisabledState 处理完 CMD_WIFI_TOGGLED 后退出,进入 EnabledState,系统保持 WiFi 打开,等待连接。

📌八、ClientModeStateMachine 对初始化消息的处理流程

从上流程可知,“ClientModeStateMachine.CMD_START”和“ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE”两条消息还处于待处理状态。
ClientModeStateMachine类构造函数可知,状态机初始状态为mIdleState,此时,将执行IdleState.enter()方法进入该状态,并开始处理CMD_START消息。

private class IdleState extends State {
 
... ... ... ...
 
case CMD_START:
 
// Always start in scan mode first.
 
mClientInterfaceName =mWifiNative.setupInterfaceForClientInScanMode(
 
mWifiNativeInterfaceCallback);
 
if (TextUtils.isEmpty(mClientInterfaceName)) {
 
Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
 
mModeListener.onStartFailure();
 
break;
 
}
 
transitionTo(mScanOnlyModeState);
 
break;
 
... ... ... ...

在处理CMD_START消息时,将调用WifiNative类中setupInterfaceForClientInScanMode()方法。


📌九、WifiNative 接口初始化的核心实现

先看WifiNative类中该方法的实现

android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
 
public String setupInterfaceForClientInScanMode(
 
@NonNull InterfaceCallback interfaceCallback) {
 
synchronized (mLock) {
 
//startwifi 加载WiFi驱动
 
if (!startHal()) {
 
Log.e(TAG, "Failed to start Hal");
 
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
 
return null;
 
}
 
//分配对应的接口
 
Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
 
if (iface == null) {
 
Log.e(TAG, "Failed to allocate new STA iface");
 
return null;
 
}
 
iface.externalListener = interfaceCallback;
 
//创建对应的station接口
 
iface.name = createStaIface(iface);
 
if (TextUtils.isEmpty(iface.name)) {
 
Log.e(TAG, "Failed to create iface in vendor HAL");
 
mIfaceMgr.removeIface(iface.id);
 
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
 
return null;
 
}
 
//设置客户端接口
 
if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
 
new NormalScanEventCallback(iface.name),
 
new PnoScanEventCallback(iface.name))) {
 
Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
 
teardownInterface(iface.name);
 
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
 
return null;
 
}
 
//设置接口up/down的检测通知
 
iface.networkObserver = new NetworkObserverInternal(iface.id);
 
if (!registerNetworkObserver(iface.networkObserver)) {
 
Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
 
teardownInterface(iface.name);
 
return null;
 
}
 
//启动wpa_supplicant事件监听
 
mWifiMonitor.startMonitoring(iface.name);
 
onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
 
//获取WiFi支持的feature
 
iface.featureSet = getSupportedFeatureSetInternal(iface.name);
 
return iface.name;
 
}
 
}
  1. startHal方法内部调用
    startHal()->startHal()->WifiVendorHal.startVendorHal()->HalDeviceManager.start()->HalDeviceManager.startWifi()
    这里看下启动WiFi的方法“HalDeviceManager.startWifi()”。在这个方法中,将加载WiFi驱动。
private boolean startWifi() {
 
... ... ... ...
 
synchronized (mLock) {
 
try {
 
if (mWifi == null) {
 
return false;
 
} else {
 
int triedCount = 0;
 
//加载WiFi驱动将尝试4次,START_HAL_RETRY_TIMES=3。
 
while (triedCount <= START_HAL_RETRY_TIMES) {
 
WifiStatus status = mWifi.start();
 
if (status.code == WifiStatusCode.SUCCESS) {
 
initIWifiChipDebugListeners();
 
managerStatusListenerDispatch();
 
if (triedCount != 0) {
 
}
 
return true;
 
} else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) {
 
try {
 
Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
 
} catch (InterruptedException ignore) {
 
// no-op
 
}
 
triedCount++;
 
} else {
 
// Should not retry on other failures.
 
Log.e(TAG, "Cannot start IWifi: " + statusString(status));
 
return false;
 
}
 
}
 
... ... ... ...

在该方法startWifi,mWifi.start()方法是启动实际加载WiFi动作的调用,这里涉及HIDL机制调用。通过获取IWifi接口对象,调用其方法。这里IWifi接口对象是IWifi.hal文件中实现。
android/hardware/interfaces/wifi/1.0/IWifi.hal在编译时,编译器会将IWifi.hal解析为IWifi.java文件,直接看该文件中的start方法实现即可。

android/out/soong//.intermediates/hardware/interfaces/wifi/1.0/android.hardware.wifi-V1.0-java_gen_java/gen/srcs/android/hardware/wifi/V1_0/IWifi.java
 
public android.hardware.wifi.V1_0.WifiStatus start() throws android.os.RemoteException {
 
try {
 
... ... ... ...
 
mRemote.transact(3 /* start */, _hidl_request, _hidl_reply, 0 /* flags */);
 
_hidl_reply.verifySuccess();
 
_hidl_request.releaseTemporaryStorage();
 
return _hidl_out_status;
 
} finally {
 
_hidl_reply.release();
 
}
 
}

通过binder调用,将调用到wifi.cpp中的start()方法。

android/hardware/interfaces/wifi/1.4/default/wifi.cpp
 
Return<void> Wifi::start(start_cb hidl_status_cb) {
 
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
 
&Wifi::startInternal, hidl_status_cb);
 
}
 
wifi.cpp->start() ==> wifi.cpp->startInternal() ==> wifi.cpp->initializeModeControllerAndLegacyHal()
 
==> WifiModeController->initialize() ==> DriverTool->LoadDriver()

通过调用DriverTool->LoadDriver将返回到Android framework中。下面是LoadDriver()的实现。

android/frameworks/opt/net/wifi/libwifi_hal/include/wifi_hal/driver_tool.cpp
 
bool DriverTool::LoadDriver() {
 
return ::wifi_load_driver() == 0;
 
}

在wifi_load_driver()方法中,将调用系统接口加载WiFi驱动ko。关于系统insmod接口的调用,本文不做分析。到这里,已梳理完在WifiNative类中调用的startHal()方法。

android/frameworks/opt/net/wifi/libwifi_hal/wifi_hal_common.cpp
 
int wifi_load_driver() {
 
... ... ... ...
 
insmod(file,args);
 
... ... ... ...
 
}
  1. 调用WifiNl80211Manager类的setupInterfaceForClientMode()方法。
    该类的主要对WiFi 80211nl管理接口的封装,接口在WiFicond守护进程中呈现给WiFi框架。该类提供的接口仅使用与WiFi框架,访问权限受selinux权限保护。
    setupInterfaceForClientMode()方法主要为Station模式设置接口。
android/frameworks/base/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
 
public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
 
@NonNull @CallbackExecutor Executor executor,
 
@NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
 
... ... ... ...
 
// Refresh Handlers
 
mClientInterfaces.put(ifaceName, clientInterface);
 
try {
 
IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
 
mWificondScanners.put(ifaceName, wificondScanner);
 
Binder.allowBlocking(wificondScanner.asBinder());
 
ScanEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback);
 
mScanEventHandlers.put(ifaceName, scanEventHandler);
 
wificondScanner.subscribeScanEvents(scanEventHandler);
 
PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor,
 
pnoScanCallback);
 
mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler);
 
wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
 
... ... ... ...
 
}

到这里,ClientModeStateMachine状态机在IdleState状态成功处理完了CMD_START消息。状态机将转到“mScanOnlyModeState”状态,将会执行以下调用流程(具体原因可查看状态机机制)。

IdleState.exit()->StartedState.enter()->StartedState.exit()->ScanOnlyModeState.enter()。

在状态转时,在StartedState.exit()中,将调用setOperationalMode方法。

public void exit() {
 
mClientModeImpl.setOperationalMode(ClientModeImpl.DISABLED_MODE, null);
 
}

📌十、ClientModeImpl 的状态机与模式管理

这里将触及开篇提到的ClientModeImpl类。首先看下其构造函数,除了其他对象赋值初始化外,又一个状态机将与我们见面。

android/frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java
 
public ClientModeImpl(.......){
 
super(TAG, looper);
 
... ... .... ....
 
// CHECKSTYLE:OFF IndentationCheck
 
addState(mDefaultState);
 
addState(mConnectModeState, mDefaultState);
 
addState(mL2ConnectedState, mConnectModeState);
 
addState(mObtainingIpState, mL2ConnectedState);
 
addState(mConnectedState, mL2ConnectedState);
 
addState(mRoamingState, mL2ConnectedState);
 
addState(mDisconnectingState, mConnectModeState);
 
addState(mDisconnectedState, mConnectModeState);
 
// CHECKSTYLE:ON IndentationCheck
 
 
 
setInitialState(mDefaultState);
 
... ... .... ....
 
}
 
public void setOperationalMode(int mode, String ifaceName) {
 
... ... ...
 
//打开WiFi mode=2,因此状态机进入到mDefaultState状态
 
if (mode != CONNECT_MODE) {
 
// we are disabling client mode... need to exit connect mode now
 
transitionTo(mDefaultState);
 
} else {
 
... ... ... ...
 
}
 
}

📌十一、切换到连接模式的完整流程

目前,还遗留一个消息“ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE”待处理。此时,轮到该消息要被处理了。
ClientModeStateMachine状态机已处于“ScanOnlyModeState”状态,接收到该消息后,在processMessage方法中并未处理,而抛给父状态“StartedState”处理。在StartedState.processMessage()方法中对该消息进行了处理。

public boolean processMessage(Message message) {
 
... ... ... ...
 
case CMD_SWITCH_TO_CONNECT_MODE:
 
mRole = message.arg1; // could be any one of possible connect mode roles.
 
//更新WiFi打开状态,发送系统广播通知。
 
updateConnectModeState(WifiManager.WIFI_STATE_ENABLING,
 
WifiManager.WIFI_STATE_DISABLED);
 
//切换设置clinent接口到连接模式。
 
if (!mWifiNative.switchClientInterfaceToConnectivityMode(
 
mClientInterfaceName)) {
 
... ... ... ...
 
mModeListener.onStartFailure();
 
break;
 
}
 
... ... ... ...
 
transitionTo(mConnectModeState);
 
break;
 
}

WifiNative类中,mWifiNative.switchClientInterfaceToConnectivityMode()方法

public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName) {
 
synchronized (mLock) {
 
... ... ... ...
 
//获取设置的接口
 
final Iface iface = mIfaceMgr.getIface(ifaceName);
 
if (iface == null) {
 
return false;
 
}
 
if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
 
return true;
 
}
 
//调用启动wpa_supplicant服务进程
 
if (!startSupplicant()) {
 
teardownInterface(iface.name);
 
mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
 
return false;
 
}
 
//注册设置接口
 
if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
 
return false;
 
}
 
iface.type = Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY;
 
iface.featureSet = getSupportedFeatureSetInternal(iface.name);
 
... ... ... ...
 
return true;
 
}
 
}
WifiNative.startSupplicant()->WifiNative.startAndWaitForSupplicantConnection()->
SupplicantStaIfaceHal.startDaemon()->SupplicantStaIfaceHal.startDaemon_V1_1()->
SupplicantStaIfaceHal.getSupplicantMockableV1_1()->
SupplicantStaIfaceHal.getSupplicantMockable()

这里看下getSupplicantMockable()方法,将在getService的时候启动wpa_supplicant进程。

通过HIDL调用获取wpa_supplicant服务。ISupplicant.getService(supplicantName)调用到ISupplicant.java。

protected ISupplicant getSupplicantMockable() throws RemoteException, NoSuchElementException {
 
synchronized (mLock) {
 
ISupplicant iSupplicant = ISupplicant.getService(supplicantName);
 
if (iSupplicant == null) {
 
throw new NoSuchElementException("Cannot get root service.");
 
}
 
return iSupplicant;
 
}
 
}
android/out/soong/intermediates/hardware/interfaces/wifi/supplicant/1.0/android.hardware.wifi.supplicant-V1.0-java_gen_java/gen/srcs/android/hardware/wifi/supplicant/V1_0/ISupplicant.java
public static ISupplicant getService(String serviceName) throws android.os.RemoteException {
 
return ISupplicant.asInterface(android.os.HwBinder.getService("android.hardware.wifi.supplicant@1.0::ISupplicant", serviceName));
 
}

在这个方法中将触发启动wpa_supplicant进程,这里需要注意,在manifest.xml中对其需要进行配置,运行时会将服务名称注册到hwservicemanager中。

wpa_supplicant目录下文件调用:

main.c ==> wpa_supplicant.c->wpa_supplicant_init() ==> notify.c->wpas_notify_supplicant_initialized() ==> hidl.cpp->wpas_hidl_init() ==> Hidl_manager.cpp->registerHidlService()
int HidlManager::registerHidlService(struct wpa_global *global)
 
{
 
// Create the main hidl service object and register it.
 
supplicant_object_ = new Supplicant(global);
 
if (supplicant_object_->registerAsService("wpa_supplicant") != android::NO_ERROR) {
 
return 1;
 
}
 
return 0;
 
}

📁附言

概念

  1. Android WLAN 架构
  2. AP、STA
  • AP(Access Point)模式:热点,发送WiFi
  • STA(Station)模式:连接WiFi的客户端
  1. mac80211、cfg80211和nl80211
  • mac80211:是一个Linux内核子系统,是驱动开发者可用于为SoftMAC无线设备写驱动的框架。mac80211在内核空间实现STA模式,在用户空间实现AP模式(hostapd)。
  • cfg80211:用于对无线设备进行配置管理,与FullMAC,mac80211和nl80211一起工作。
  • nl80211:用于对无线设备进行配置管理,它是一个基本Netlink的用户态协议。

参考文章

  1. Android 11 WiFi启动流程_incrementnumwifitoggles-CSDN博客
  2. 概览  |  Android Open Source Project