前言
当通过安卓UI界面打开WIFI时,我们直观的能看到WIFI被打开并且开始了扫描。这其中当然包含了一些我们看不到的流程,包括加载驱动、打开设备、扫描等等动作。而这些动作也离不开底层驱动的处理,那么我们就以底层的视角去看看上层是如何一步步最终调用到底层驱动的吧。
一、加载驱动
既然要从上层开始,那么就要从UI界面打开WIFI以后触发的函数开始(文件:函数):
[WifiStateSwitchPreferenceController.java : handlePreferenceChanged]
protected boolean handlePreferenceChanged(ColoredSwitchPreference preference,
Object newValue) {
boolean wifiEnabled = (Boolean) newValue;
getCarWifiManager().setWifiEnabled(wifiEnabled);
return true;
}
WifiStateSwitchPreferenceController.java主要是用来管理WIFI开关状态,当WIFI 由OFF变为ON时,此函数就会被调用。接着往下继续看:
[CarWifiManager.java :setWifiEnabled]
public boolean setWifiEnabled(boolean enabled) {
return mWifiManager.setWifiEnabled(enabled);
}
这种就不多说了,接着往下跟踪:
[WifiManager.java :setWifiEnabled]
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
调用到WIFI服务实现中:
[WifiServiceImpl.java :setWifiEnabled]
public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
...
setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged);
return true;
}
有些不是重点我们略过,直接看函数最后的调用:
private void setWifiEnabledInternal(String packageName, boolean enable,
int callingUid, int callingPid, boolean isPrivileged) {
...
mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
mWifiMetrics.reportWifiStateChanged(enable, mWifiInjector.getWakeupController().isUsable(),
false);
mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName));
mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED, Process.myTid(),
callingUid, callingPid, packageName, enable);
}
}
wifiToggled这个函数看名字就叫WIFI切换嘛,那就直接往里看:
[ActiveModeWarden.java :wifiToggled]
public void wifiToggled(WorkSource requestorWs) {
mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
}
这个函数就干了一件事,那就是往状态机发送了CMD_WIFI_TOGGLED命令,那么就要看当前状态下状态机的对应处理了。
在ActiveModeWarden.java文件中,由于默认状态是DisabledState状态,直接看当前状态机下的处理函数:
public boolean processMessageFiltered(Message msg) {
switch (msg.what) {
case CMD_WIFI_TOGGLED:
case CMD_SCAN_ALWAYS_MODE_CHANGED:
handleStaToggleChangeInDisabledState((WorkSource) msg.obj);
break;
...
后面的处理我们省略,直接看CMD_WIFI_TOGGLED命令下的处理函数如下:
private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) {
if (shouldEnableSta()) {
startPrimaryOrScanOnlyClientModeManager(requestorWs);
transitionTo(mEnabledState);
}
}
这个函数也很明显,startPrimaryOrScanOnlyClientModeManager是对应的具体处理函数,执行后会将状态机从DisabledState迁移到EnabledState状态。
继续往下看:
private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
if (role == ROLE_CLIENT_PRIMARY) {
return startPrimaryClientModeManager(requestorWs);
} else if (role == ROLE_CLIENT_SCAN_ONLY) {
return startScanOnlyClientModeManager(requestorWs);
} else {
return false;
}
}
这里有个角色的判断,看当前的角色是客户端还是仅扫描。客户端就是通常我们作为客户端去连接对端wifi,也就是STA模式。仅扫描只会触发扫描动作,并不会去连接网络。因此这里我们作为正常的客户端开启,直接看startPrimaryClientModeManager即可:
private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
if (hasPrimaryOrScanOnlyModeManager()) {
Log.e(TAG, "Unexpected state - primary CMM should not be started when a primary "
+ "or scan only CMM is already present.");
if (!mIsMultiplePrimaryBugreportTaken) {
mIsMultiplePrimaryBugreportTaken = true;
mWifiDiagnostics.takeBugReport("Wi-Fi ActiveModeWarden bugreport",
"Trying to start primary mode manager when one already exists.");
}
return false;
}
Log.d(TAG, "Starting primary ClientModeManager in connect mode");
ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
mClientModeManagers.add(manager);
mLastPrimaryClientModeManagerRequestorWs = requestorWs;
return true;
}
这里通过注入器创建了一个ConcreteClientModeManager实例并添加到管理器列表中。我们直接看创建的流程:
[WifiInjector.java :makeClientModeManager]
public ConcreteClientModeManager makeClientModeManager(
@NonNull ClientModeManager.Listener<ConcreteClientModeManager> listener,
@NonNull WorkSource requestorWs,
@NonNull ActiveModeManager.ClientRole role,
boolean verboseLoggingEnabled) {
return new ConcreteClientModeManager(
mContext, mWifiHandlerThread.getLooper(), mClock,
mWifiNative, listener, mWifiMetrics, mWakeupController,
this, mSelfRecovery, mWifiGlobals, mDefaultClientModeManager,
mClock.getElapsedSinceBootMillis(), requestorWs, role, mBroadcastQueue,
verboseLoggingEnabled);
}
new构建了一个ConcreteClientModeManager对象:
[ConcreteClientModeManager.java :ConcreteClientModeManager]
ConcreteClientModeManager(
Context context, @NonNull Looper looper, Clock clock,
WifiNative wifiNative, @NonNull Listener<ConcreteClientModeManager> listener,
WifiMetrics wifiMetrics,
WakeupController wakeupController, WifiInjector wifiInjector,
SelfRecovery selfRecovery, WifiGlobals wifiGlobals,
DefaultClientModeManager defaultClientModeManager, long id,
@NonNull WorkSource requestorWs, @NonNull ClientRole role,
@NonNull ClientModeManagerBroadcastQueue broadcastQueue,
boolean verboseLoggingEnabled) {
mContext = context;
mClock = clock;
mWifiNative = wifiNative;
mModeListener = listener;
mWifiMetrics = wifiMetrics;
mWakeupController = wakeupController;
mWifiInjector = wifiInjector;
mStateMachine = new ClientModeStateMachine(looper);
mDeferStopHandler = new DeferStopHandler(looper);
mSelfRecovery = selfRecovery;
mWifiGlobals = wifiGlobals;
mDefaultClientModeManager = defaultClientModeManager;
mId = id;
mTargetRoleChangeInfo = new RoleChangeInfo(role, requestorWs, listener);
mBroadcastQueue = broadcastQueue;
enableVerboseLogging(verboseLoggingEnabled);
mStateMachine.sendMessage(ClientModeStateMachine.CMD_START, mTargetRoleChangeInfo);
}
这个函数首先通过ClientModeStateMachine构建了一个状态机,最后往状态机发送了CMD_START命令。这里的状态机初始化为IdleState,那么直接看对应的处理吧:
public boolean processMessageImpl(Message message) {
if (mVerboseLoggingEnabled) {
Log.d(getTag(),
getName() + " cmd = " + getWhatToString(message.what) + " "
+ message.toString());
}
switch (message.what) {
case CMD_START:
// Always start in scan mode first.
RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj;
mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode(
mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs,
ConcreteClientModeManager.this);
if (TextUtils.isEmpty(mClientInterfaceName)) {
Log.e(getTag(), "Failed to create ClientInterface. Sit in Idle");
takeBugReportInterfaceFailureIfNeeded(
"Wi-Fi BugReport (scan STA interface failure):",
"Failed to create client interface in idle state");
mModeListener.onStartFailure(ConcreteClientModeManager.this);
break;
}
mWifiNative.setWifiNativeInterfaceEventCallback(
mWifiNativeInterfaceEventCallback);
if (roleChangeInfo.role instanceof ClientConnectivityRole) {
sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo);
transitionTo(mStartedState);
} else {
mScanRoleChangeInfoToSetOnTransition = roleChangeInfo;
transitionTo(mScanOnlyModeState);
}
break;
...
这里第一个处理是调用了wifinative的setupInterfaceForClientInScanMode函数,看到wifinative那大概率是要往下层做一些处理动作了。等会我们细看这个函数的处理,先看看后面接着做了什么,条件判断中我们仍然看客户端的条件下的处理。在完成了上述动作以后,发送了一个CMD_SWITCH_TO_CONNECT_MODE命令看起来是已经打开wifi并进入了连接模式,同时状态机迁移到StartedState状态。
先看setupInterfaceForClientInScanMode函数处理实现:
[WifiNative.java :setupInterfaceForClientInScanMode]
public String setupInterfaceForClientInScanMode(
@NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs,
@NonNull ConcreteClientModeManager concreteClientModeManager) {
synchronized (mLock) {
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;
iface.name = createStaIface(iface, requestorWs, concreteClientModeManager);
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;
}
registerInterfaceObserver();
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;
}
mWifiMonitor.startMonitoring(iface.name);
// Just to avoid any race conditions with interface state change callbacks,
// update the interface state before we exit.
onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
mWifiVendorHal.enableLinkLayerStats(iface.name);
Log.i(TAG, "Successfully setup " + iface);
iface.featureSet = getSupportedFeatureSetInternal(iface.name);
updateSupportedBandForStaInternal(iface);
mWifiVendorHal.enableStaChannelForPeerNetwork(mContext.getResources().getBoolean(
R.bool.config_wifiEnableStaIndoorChannelForPeerNetwork),
mContext.getResources().getBoolean(
R.bool.config_wifiEnableStaDfsChannelForPeerNetwork));
return iface.name;
}
}
在这个函数中主要执行了这么几个处理:
startHal:开始启动halcreateStaIface:创建了sta接口setupInterfaceForClientMode:为客户端设置网络接口startMonitoring:然后是监控
先从startHal开始看:
private boolean startHal() {
synchronized (mLock) {
if (!mIfaceMgr.hasAnyIface()) {
if (mWifiVendorHal.isVendorHalSupported()) {
if (!mWifiVendorHal.startVendorHal()) {
Log.e(TAG, "Failed to start vendor HAL");
return false;
}
if (SdkLevel.isAtLeastS()) {
mWifiVendorHal.setCoexUnsafeChannels(
mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
}
} else {
Log.i(TAG, "Vendor Hal not supported, ignoring start.");
}
}
registerWificondListenerIfNecessary();
return true;
}
}
直接看startVendorHal:
[WifiVendorHal.java :startVendorHal]
public boolean startVendorHal() {
synchronized (sLock) {
if (!mHalDeviceManager.start()) {
mLog.err("Failed to start vendor HAL").flush();
return false;
}
mLog.info("Vendor Hal started successfully").flush();
return true;
}
}
接着看start:
[HalDeviceManager.java :start]
public boolean start() {
return startWifi();
}
private boolean startWifi() {
if (VDBG) Log.d(TAG, "startWifi");
initializeInternal();
synchronized (mLock) {
int triedCount = 0;
while (triedCount <= START_HAL_RETRY_TIMES) {
int status = mWifiHal.start();
if (status == WifiHal.WIFI_STATUS_SUCCESS) {
managerStatusListenerDispatch();
if (triedCount != 0) {
Log.d(TAG, "start IWifi succeeded after trying "
+ triedCount + " times");
}
WifiChipInfo[] wifiChipInfos = getAllChipInfo();
if (wifiChipInfos == null) {
Log.e(TAG, "Started wifi but could not get current chip info.");
}
return true;
} else if (status == WifiHal.WIFI_STATUS_ERROR_NOT_AVAILABLE) {
// Should retry. Hal might still be stopping. the registered event
// callback will not be cleared.
Log.e(TAG, "Cannot start wifi because unavailable. Retrying...");
try {
Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
} catch (InterruptedException ignore) {
// no-op
}
triedCount++;
} else {
// Should not retry on other failures.
// Will be handled in the onFailure event.
Log.e(TAG, "Cannot start IWifi. Status: " + status);
return false;
}
}
Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
return false;
}
}
mWifiHal.start()如下:
[WifiHal.java :start]
public @WifiStatusCode int start() {
return validateAndCall("start", WIFI_STATUS_ERROR_UNKNOWN,
() -> mWifiHal.start());
}
mWifiHal.start()最终通过IWifiHal.java调用到WifiHalAidlImpl.java:
[WifiHalAidlImpl.java :start]
public @WifiHal.WifiStatusCode int start() {
final String methodStr = "start";
synchronized (mLock) {
try {
if (!checkWifiAndLogFailure(methodStr)) return WifiHal.WIFI_STATUS_ERROR_UNKNOWN;
mWifi.start();
return WifiHal.WIFI_STATUS_SUCCESS;
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
return WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION;
} catch (ServiceSpecificException e) {
handleServiceSpecificException(e, methodStr);
return halToFrameworkWifiStatusCode(e.errorCode);
}
}
}
这个函数中的mWifi.start()就会通过AIDL调用到Hal层中,也就是从java代码转到了cpp代码中了:
[wifi.cpp :start]
ndk::ScopedAStatus Wifi::start() {
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal);
}
ndk::ScopedAStatus Wifi::startInternal() {
if (run_state_ == RunState::STARTED) {
return ndk::ScopedAStatus::ok();
} else if (run_state_ == RunState::STOPPING) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
}
ndk::ScopedAStatus wifi_status = initializeModeControllerAndLegacyHal();
...
return wifi_status;
}
initializeModeControllerAndLegacyHal用来初始化相关的控制器和Hal:
ndk::ScopedAStatus Wifi::initializeModeControllerAndLegacyHal() {
if (!mode_controller_->initialize()) {
LOG(ERROR) << "Failed to initialize firmware mode controller";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
legacy_hals_ = legacy_hal_factory_->getHals();
if (legacy_hals_.empty()) return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
int index = 0; // for failure log
for (auto& hal : legacy_hals_) {
legacy_hal::wifi_error legacy_status = hal->initialize();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
// Currently WifiLegacyHal::initialize does not allocate extra mem,
// only initializes the function table. If this changes, need to
// implement WifiLegacyHal::deinitialize and deinitalize the
// HALs already initialized
LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
<< " error: " << legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
index++;
}
return ndk::ScopedAStatus::ok();
}
看一下mode控制器的初始化处理:
[wifi_mode_controller.cpp :initialize]
bool WifiModeController::initialize() {
if (!driver_tool_->LoadDriver()) {
LOG(ERROR) << "Failed to load WiFi driver";
return false;
}
return true;
}
这里调用了驱动工具中的LoadDriver函数来加载驱动:
[driver_tool.cpp :LoadDriver]
bool DriverTool::LoadDriver() {
return ::wifi_load_driver() == 0;
}
wifi_load_driver实现:
[wifi_hal_common.cpp :wifi_load_driver]
int wifi_load_driver() {
#ifdef WIFI_DRIVER_MODULE_PATH
if (is_wifi_driver_loaded()) {
return 0;
}
if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) return -1;
#endif
#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
if (is_wifi_driver_loaded()) {
return 0;
}
if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0) {
#ifdef WIFI_DRIVER_MODULE_PATH
PLOG(WARNING) << "Driver unloading, err='fail to change driver state'";
if (rmmod(DRIVER_MODULE_NAME) == 0) {
PLOG(DEBUG) << "Driver unloaded";
} else {
// Set driver prop to "ok", expect HL to restart Wi-Fi.
PLOG(DEBUG) << "Driver unload failed! set driver prop to 'ok'.";
property_set(DRIVER_PROP_NAME, "ok");
}
#endif
return -1;
}
#endif
is_driver_loaded = true;
return 0;
}
这个函数首先会判断驱动是否被加载,如果已经被加载则直接退出即可。若是没有加载将通过insmod来加载驱动。但是在Qcom工程中,实际这里并不会走,WIFI驱动已经被加载过了,所以这里仅wifi_change_driver_state函数会被调用:
int wifi_change_driver_state(const char *state) {
int len;
int fd;
int ret = 0;
struct timespec req;
req.tv_sec = 0;
req.tv_nsec = kDriverStateAccessRetrySleepMillis * 1000000L;
int count = 5; /* wait at most 1 second for completion. */
if (!state) return -1;
do {
if (access(WIFI_DRIVER_STATE_CTRL_PARAM, W_OK) == 0)
break;
nanosleep(&req, (struct timespec *)NULL);
} while (--count > 0);
if (count == 0) {
PLOG(ERROR) << "Failed to access driver state control param "
<< strerror(errno) << ", " << errno;
return -1;
}
fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
if (fd < 0) {
PLOG(ERROR) << "Failed to open driver state control param";
return -1;
}
len = strlen(state) + 1;
if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
PLOG(ERROR) << "Failed to write driver state control param";
ret = -1;
}
close(fd);
return ret;
}
这一函数具体就是通过open打开/dev/wlan设备,然后使用write往设备节点中写入ON或OFF字符串来通知底层设备。
最终调用到WLAN驱动wlan_hdd_main.c文件中的wlan_hdd_state_ctrl_param_write函数
const struct file_operations wlan_hdd_state_fops = {
.owner = THIS_MODULE,
.open = wlan_hdd_state_ctrl_param_open,
.write = wlan_hdd_state_ctrl_param_write,
.release = wlan_hdd_state_ctrl_param_release,
};
这一函数实际没什么讲的,里面没有太多的具体实现,无非是打印了一条我们在打开wifi设备时经常看到的log:
hdd_info("Wifi Turning On from UI\n");
...
hdd_inform_wifi_on();
这篇先到这里吧,后面继续讲解wifi打开的流程
&spm=1001.2101.3001.5002&articleId=142338628&d=1&t=3&u=98cd209885e542cca5a0a5f2687e991a)
3504

被折叠的 条评论
为什么被折叠?



