记一次rk平台热点打开流程追踪记录
问题描述
rk平台偶现热点打开失败,错误日志如下:
I/android.hardware.wifi@1.0-service: Starting legacy HAL
E/android.hardware.wifi@1.0-service: Could not set interface flags for wlan0 (Operation not permitted)
E/android.hardware.wifi@1.0-service: Failed to set WiFi interface up
E/android.hardware.wifi@1.0-service: Failed to start legacy HAL: UNKNOWN
E/HalDevMgr: executeChipReconfiguration: configureChip error: 9 (unknown)
E/WifiVendorHal: Failed to create AP iface
E/WifiNative: Failed to create AP iface in vendor HAL
E/SoftApManager: setup failure when creating ap interface.
V/WifiManager: SoftApCallbackProxy: onStateChanged: state=14, failureReason=0
E/WifiController: SoftAP start failed
故借此机会准备从Java层开始学习热点的打开流程
开始
1.首先,我们要打开热点,调用是ConnectivityManager中的如下方法:
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
ResultReceiver wrappedCallback = new ResultReceiver(handler) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode == TETHER_ERROR_NO_ERROR) {
callback.onTetheringStarted();
} else {
callback.onTetheringFailed();
}
}
};
try {
String pkgName = mContext.getOpPackageName();
Log.i(TAG, "startTethering caller:" + pkgName);
mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
} catch (RemoteException e) {
Log.e(TAG, "Exception trying to start tethering.", e);
wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
}
}
此方法有四个参数:
type:热点类型,有三种TETHERING_WIFI、TETHERING_USB、TETHERING_BLUETOOTH(一般我们用到的个人热点就是TETHERING_WIFI)
showProvisioningUi:当设置为true是,将展示一个类似使用帮助的页面(需要厂商自己实现)
callback:热点打开结果的回调
handler:可以指定执行上面回调函数的线程
2.找到ConnectivityService的startTethering方法
@Override
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (!isTetheringSupported()) {
receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
return;
}
mTethering.startTethering(type, receiver, showProvisioningUi);
}
显示权限检查,注释已经写的很明白了,之后判断是否支持热点,之后就调到了Tethering中的startTethering方法
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
if (!isTetherProvisioningRequired()) {//当没有定义热点UI时就会直接打开热点
enableTetheringInternal(type, true, receiver);
return;
}
if (showProvisioningUi) {
runUiTetherProvisioningAndEnable(type, receiver);
} else {
runSilentTetherProvisioningAndEnable(type, receiver);
}
}
接下来看enableTetheringInternal方法
/**
* Enables or disables tethering for the given type. This should only be called once
* provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
* for the specified interface.
*/
private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
int result;
switch (type) {
case TETHERING_WIFI:
result = setWifiTethering(enable);
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
case TETHERING_USB:
result = setUsbTethering(enable);
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
case TETHERING_BLUETOOTH:
setBluetoothTethering(enable, receiver);
break;
default:
Log.w(TAG, "Invalid tether type.");
sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
}
}
主要看TETHERING_WIFI
private int setWifiTethering(final boolean enable) {
int rval = TETHER_ERROR_MASTER_ERROR;
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mPublicSync) {
mWifiTetherRequested = enable;
final WifiManager mgr = getWifiManager();
if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
(!enable && mgr.stopSoftAp())) {
rval = TETHER_ERROR_NO_ERROR;
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return rval;
}
3.找到startSoftAp的实现,在WifiServiceImpl.java中
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
/**
* see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
* @param wifiConfig SSID, security and channel details as part of WifiConfiguration
* @return {@code true} if softap start was triggered
* @throws SecurityException if the caller does not have permission to start softap
*/
@Override
public boolean startSoftAp(WifiConfiguration wifiConfig) {
// NETWORK_STACK is a signature only permission.
enforceNetworkStackPermission();
mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
synchronized (mLocalOnlyHotspotRequests) {
// If a tethering request comes in while we have LOHS running (or requested), call stop
// for softap mode and restart softap with the tethering config.
if (!mLocalOnlyHotspotRequests.isEmpty()) {
stopSoftApInternal();
}
return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
}
}
/**
* Internal method to start softap mode. Callers of this method should have already checked
* proper permissions beyond the NetworkStack permission.
*/
private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
mLog.trace("startSoftApInternal uid=% mode=%")
.c(Binder.getCallingUid()).c(mode).flush();
// null wifiConfig is a meaningful input for CMD_SET_AP
if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
return true;
}
Slog.e(TAG, "Invalid WifiConfiguration");
return false;
}
4.接着到WifiController.java这是个状态机,真正操作打开热点是在WifiStateMachinePrime.java中:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java
/**
* Method to enable soft ap for wifi hotspot.
*
* The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
* the persisted config is to be used) and the target operating mode (ex,
* {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
*
* @param wifiConfig SoftApModeConfiguration for the hostapd softap
*/
public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
mHandler.post(() -> {
startSoftAp(wifiConfig);
});
}
private void startSoftAp(SoftApModeConfiguration softapConfig) {
Log.d(TAG, "Starting SoftApModeManager");
WifiConfiguration config = softapConfig.getWifiConfiguration();
if (config != null && config.SSID != null) {
Log.d(TAG, "Passing config to SoftApManager! " + config);
} else {
config = null;
}
SoftApCallbackImpl callback = new SoftApCallbackImpl();
ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
callback.setActiveModeManager(manager);
manager.start();
mActiveModeManagers.add(manager);
updateBatteryStatsWifiState(true);
}
5.找到SoftApManager.java的start()方法:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java
/**
* Start soft AP with the supplied config.
*/
public void start() {
mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
}
又一个状态机
private class IdleState extends State {
@Override
public void enter() {
mApInterfaceName = null;
mIfaceIsUp = false;
}
@Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
Log.e(TAG, "CMD_START.");
mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
mWifiNativeInterfaceCallback);
if (TextUtils.isEmpty(mApInterfaceName)) {
Log.e(TAG, "setup failure when creating ap interface.");
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.WIFI_AP_STATE_DISABLED,
WifiManager.SAP_START_FAILURE_GENERAL);
mWifiMetrics.incrementSoftApStartResult(
false, WifiManager.SAP_START_FAILURE_GENERAL);
break;
}
updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
WifiManager.WIFI_AP_STATE_DISABLED, 0);
int result = startSoftAp((WifiConfiguration) message.obj);
if (result != SUCCESS) {
int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
if (result == ERROR_NO_CHANNEL) {
failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
}
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.WIFI_AP_STATE_ENABLING,
failureReason);
stopSoftAp();
mWifiMetrics.incrementSoftApStartResult(false, failureReason);
break;
}
transitionTo(mStartedState);
break;
default:
// Ignore all other commands.
break;
}
return HANDLED;
}
}
6.setupInterfaceForSoftApMode方法,此处就比较重要了,需要逐条分析:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
/**
* Setup an interface for Soft AP mode operations.
*
* This method configures an interface in AP mode in all the native daemons
* (wificond, wpa_supplicant & vendor HAL).
*
* @param interfaceCallback Associated callback for notifying status changes for the iface.
* @return Returns the name of the allocated interface, will be null on failure.
*/
public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) {
Log.e(TAG,"setupInterfaceForSoftApMode");
synchronized (mLock) {
if (!startHal()) {
Log.e(TAG, "Failed to start Hal");
mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
return null;
}
Log.e(TAG, "liyang Hal start success");
Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP);
if (iface == null) {
Log.e(TAG, "Failed to allocate new AP iface");
return null;
}
iface.externalListener = interfaceCallback;
iface.name = createApIface(iface);
if (TextUtils.isEmpty(iface.name)) {
Log.e(TAG, "Failed to create AP iface in vendor HAL");
mIfaceMgr.removeIface(iface.id);
mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
return null;
}
if (mWificondControl.setupInterfaceForSoftApMode(iface.name) == null) {
Log.e(TAG, "Failed to setup iface in wificond on " + iface);
teardownInterface(iface.name);
mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond();
return null;
}
iface.networkObserver = new NetworkObserverInternal(iface.id);
if (!registerNetworkObserver(iface.networkObserver)) {
Log.e(TAG, "Failed to register network observer on " + iface);
teardownInterface(iface.name);
return null;
}
// Just to avoid any race conditions with interface state change callbacks,
// update the interface state before we exit.
onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
Log.i(TAG, "Successfully setup " + iface);
return iface.name;
}
}
7先看startHal()方法:
/** Helper method invoked to start supplicant if there were no ifaces */
private boolean startHal() {
synchronized (mLock) {
if (!mIfaceMgr.hasAnyIface()) {
if (mWifiVendorHal.isVendorHalSupported()) {
if (!mWifiVendorHal.startVendorHal()) {
Log.e(TAG, "Failed to start vendor HAL");
return false;
}
} else {
Log.i(TAG, "Vendor Hal not supported, ignoring start.");
}
}
return true;
}
}
首次进来,还未调用 allocateIface 方法,所以 mIfaceMgr.hasAnyIface() 为 false,
同时mWifiVendorHal.isVendorHalSupported()也必然为true,接着就到了WifiVendorHal.java中:
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java
/**
* Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
*
* @return true for success
*/
public boolean startVendorHalAp() {
synchronized (sLock) {
if (!startVendorHal()) {
return false;
}
if (TextUtils.isEmpty(createApIface(null))) {
stopVendorHal();
return false;
}
return true;
}
}
/**
* Bring up the HIDL Vendor HAL.
* @return true on success, false otherwise.
*/
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;
}
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/HalDeviceManager.java
/**
* Attempts to start Wi-Fi (using HIDL). Returns the success (true) or failure (false) or
* the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
* success.
*
* Note: direct call to HIDL.
*/
public boolean start() {
return startWifi();
}
private boolean startWifi() {
if (VDBG) Log.d(TAG, "startWifi");
synchronized (mLock) {
try {
if (mWifi == null) {
Log.w(TAG, "startWifi called but mWifi is null!?");
return false;
} else {
int triedCount = 0;
while (triedCount <= START_HAL_RETRY_TIMES) {
WifiStatus status = mWifi.start();
if (status.code == WifiStatusCode.SUCCESS) {
initIWifiChipDebugListeners();
managerStatusListenerDispatch();
if (triedCount != 0) {
Log.d(TAG, "start IWifi succeeded after trying "
+ triedCount + " times");
}
return true;
} else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) {
// Should retry. Hal might still be stopping.
Log.e(TAG, "Cannot start IWifi: " + statusString(status)
+ ", Retrying...");
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;
}
}
Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
return false;
}
} catch (RemoteException e) {
Log.e(TAG, "startWifi exception: " + e);
return false;
}
}
}
从 mWifi.start() 开始就到了native层
hardware/interfaces/wifi/1.2/default/wifi.cpp
Return<void> Wifi::start(start_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
&Wifi::startInternal, hidl_status_cb);
}
WifiStatus Wifi::startInternal() {
if (run_state_ == RunState::STARTED) {
return createWifiStatus(WifiStatusCode::SUCCESS);
} else if (run_state_ == RunState::STOPPING) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
"HAL is stopping");
}
WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
if (wifi_status.code == WifiStatusCode::SUCCESS) {
// Create the chip instance once the HAL is started.
chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
feature_flags_);
run_state_ = RunState::STARTED;
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onStart().isOk()) {
LOG(ERROR) << "Failed to invoke onStart callback";
};
}
LOG(INFO) << "Wifi HAL started";
} else {
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onFailure(wifi_status).isOk()) {
LOG(ERROR) << "Failed to invoke onFailure callback";
}
}
LOG(ERROR) << "Wifi HAL start failed";
}
return wifi_status;
}
WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
if (!mode_controller_->initialize()) {
LOG(ERROR) << "Failed to initialize firmware mode controller";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to initialize legacy HAL: "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
return createWifiStatus(WifiStatusCode::SUCCESS);
}
hardware/interfaces/wifi/1.2/default/wifi_mode_controller.cpp
bool WifiModeController::initialize() {
if (!driver_tool_->LoadDriver()) {
LOG(ERROR) << "Failed to load WiFi driver";
return false;
}
return true;
}
framework/opt/net/wifi/lbwifi_hal/driver_tool.cpp
bool DriverTool::LoadDriver() {
return ::wifi_load_driver() == 0;
}
frameworks/opt/net/wifi/libwifi_hal/wifi_hal_common.cpp
int wifi_load_driver() {
#ifdef WIFI_DRIVER_MODULE_PATH
char* wifi_ko_path = NULL ;
char* wifi_ko_arg =NULL;
int i = 0;
int count = 100;
if (is_wifi_driver_loaded()) {
return 0;
}
if (wifi_type[0] == 0) {
check_wifi_chip_type_string(wifi_type);
save_wifi_chip_type(wifi_type);
}
for (i=0; i< (int)(sizeof(module_list) / sizeof(module_list[0])); i++) {
if (!strcmp(wifi_type , module_list[i].wifi_name)) {
wifi_ko_path = module_list[i].wifi_module_path;
wifi_ko_arg = module_list[i].wifi_module_arg;
PLOG(ERROR) << "matched ko file path " << wifi_ko_path;
break;
}
}
if (wifi_ko_path == NULL) {
PLOG(ERROR) << "falied to find wifi driver for type=" << wifi_type;
return -1;
}
if (strstr(wifi_ko_path, MVL_DRIVER_MODULE_NAME)) {
insmod(MLAN_DRIVER_MODULE_PATH, "");
}
if (insmod(wifi_ko_path, wifi_ko_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) return -1;
#endif
while (count-- > 0) {
if (is_wifi_driver_loaded()) {
property_set(DRIVER_PROP_NAME, "ok");
return 0;
}
usleep(200000);
}
property_set(DRIVER_PROP_NAME, "timeout");
return -1;
}
这里面就开始加载wlan0模块,并通过检测/proc/net/dev节点中是否存在wlan0判断是否加载完成,具体模块的初始化在:
kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c
dhd_module_init(void)
{
int err;
int retry = 0;
printf("%s: in %s\n", __FUNCTION__, dhd_version);
DHD_PERIM_RADIO_INIT();
if (firmware_path[0] != '\0') {
strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN);
fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
}
if (nvram_path[0] != '\0') {
strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN);
nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
}
do {
err = dhd_wifi_platform_register_drv();
if (!err) {
register_reboot_notifier(&dhd_reboot_notifier);
break;
} else {
DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n",
__FUNCTION__, retry));
strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN);
firmware_path[MOD_PARAM_PATHLEN-1] = '\0';
strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN);
nvram_path[MOD_PARAM_PATHLEN-1] = '\0';
}
} while (retry--);
dhd_create_to_notifier_skt();
if (err) {
DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__));
} else {
if (!dhd_download_fw_on_driverload) {
dhd_driver_init_done = TRUE;
}
}
printf("%s: Exit err=%d\n", __FUNCTION__, err);
return err;
}
当wlan0模块加载完成后,接着看legacy_hal_->initialize(),初始化hal函数:
hardware/interfaces/wifi/1.2/default/wifi_legacy_hal.cpp
wifi_error WifiLegacyHal::initialize() {
LOG(ERROR) << "Initialize legacy HAL";
// TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
// for now is this function call which we can directly call.
if (!initHalFuncTableWithStubs(&global_func_table_)) {
LOG(ERROR)
<< "Failed to initialize legacy hal function table with stubs";
return WIFI_ERROR_UNKNOWN;
}
wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
if (status != WIFI_SUCCESS) {
LOG(ERROR) << "Failed to initialize legacy hal function table";
}
return status;
}
到此,初始化工作就完成了,下面回头看第 6 点中的 createApIface(iface) 方法
8.创建AP Iface
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
/**
* Helper function to handle creation of AP iface.
* For devices which do not the support the HAL, this will bypass HalDeviceManager &
* teardown any existing iface.
*/
private String createApIface(@NonNull Iface iface) {
synchronized (mLock) {
if (mWifiVendorHal.isVendorHalSupported()) {
return mWifiVendorHal.createApIface(
new InterfaceDestoyedListenerInternal(iface.id));
} else {
Log.i(TAG, "Vendor Hal not supported, ignoring createApIface.");
return handleIfaceCreationWhenVendorHalNotSupported(iface);
}
}
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiVendorHal.java
/**
* Create a AP iface using {@link HalDeviceManager}.
*
* @param destroyedListener Listener to be invoked when the interface is destroyed.
* @return iface name on success, null otherwise.
*/
public String createApIface(InterfaceDestroyedListener destroyedListener) {
synchronized (sLock) {
IWifiApIface iface = mHalDeviceManager.createApIface(
new ApInterfaceDestroyedListenerInternal(destroyedListener), null);
if (iface == null) {
mLog.err("Failed to create AP iface").flush();
return stringResult(null);
}
String ifaceName = mHalDeviceManager.getName((IWifiIface) iface);
if (TextUtils.isEmpty(ifaceName)) {
mLog.err("Failed to get iface name").flush();
return stringResult(null);
}
if (!retrieveWifiChip((IWifiIface) iface)) {
mLog.err("Failed to get wifi chip").flush();
return stringResult(null);
}
mIWifiApIfaces.put(ifaceName, iface);
return ifaceName;
}
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/HalDeviceManager.java
/**
* Create AP interface if possible (see createStaIface doc).
*/
public IWifiApIface createApIface(@Nullable InterfaceDestroyedListener destroyedListener,
@Nullable Handler handler) {
return (IWifiApIface) createIface(IfaceType.AP, false, destroyedListener, handler);
}
private IWifiIface createIface(int ifaceType, boolean lowPriority,
InterfaceDestroyedListener destroyedListener, Handler handler) {
if (mDbg) {
Log.d(TAG, "createIface: ifaceType=" + ifaceType + ", lowPriority=" + lowPriority);
}
synchronized (mLock) {
WifiChipInfo[] chipInfos = getAllChipInfo();
if (chipInfos == null) {
Log.e(TAG, "createIface: no chip info found");
stopWifi(); // major error: shutting down
return null;
}
if (!validateInterfaceCache(chipInfos)) {
Log.e(TAG, "createIface: local cache is invalid!");
stopWifi(); // major error: shutting down
return null;
}
IWifiIface iface = createIfaceIfPossible(chipInfos, ifaceType, lowPriority,
destroyedListener, handler);
if (iface != null) { // means that some configuration has changed
if (!dispatchAvailableForRequestListeners()) {
return null; // catastrophic failure - shut down
}
}
return iface;
}
}
/**
* Performs chip reconfiguration per the input:
* - Removes the specified interfaces
* - Reconfigures the chip to the new chip mode (if necessary)
* - Creates the new interface
*
* Returns the newly created interface or a null on any error.
*/
private IWifiIface executeChipReconfiguration(IfaceCreationData ifaceCreationData,
int ifaceType) {
if (mDbg) {
Log.d(TAG, "executeChipReconfiguration: ifaceCreationData=" + ifaceCreationData
+ ", ifaceType=" + ifaceType);
}
synchronized (mLock) {
try {
// is this a mode change?
boolean isModeConfigNeeded = !ifaceCreationData.chipInfo.currentModeIdValid
|| ifaceCreationData.chipInfo.currentModeId != ifaceCreationData.chipModeId;
if (mDbg) Log.d(TAG, "isModeConfigNeeded=" + isModeConfigNeeded);
// first delete interfaces/change modes
if (isModeConfigNeeded) {
// remove all interfaces pre mode-change
// TODO: is this necessary? note that even if we don't want to explicitly
// remove the interfaces we do need to call the onDeleted callbacks - which
// this does
for (WifiIfaceInfo[] ifaceInfos: ifaceCreationData.chipInfo.ifaces) {
for (WifiIfaceInfo ifaceInfo: ifaceInfos) {
removeIfaceInternal(ifaceInfo.iface); // ignore return value
}
}
WifiStatus status = ifaceCreationData.chipInfo.chip.configureChip(
ifaceCreationData.chipModeId);
if (status.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "executeChipReconfiguration: configureChip error: "
+ statusString(status));
return null;
}
} else {
// remove all interfaces on the delete list
for (WifiIfaceInfo ifaceInfo: ifaceCreationData.interfacesToBeRemovedFirst) {
removeIfaceInternal(ifaceInfo.iface); // ignore return value
}
}
// create new interface
Mutable<WifiStatus> statusResp = new Mutable<>();
Mutable<IWifiIface> ifaceResp = new Mutable<>();
switch (ifaceType) {
case IfaceType.STA:
ifaceCreationData.chipInfo.chip.createStaIface(
(WifiStatus status, IWifiStaIface iface) -> {
statusResp.value = status;
ifaceResp.value = iface;
});
break;
case IfaceType.AP:
ifaceCreationData.chipInfo.chip.createApIface(
(WifiStatus status, IWifiApIface iface) -> {
statusResp.value = status;
ifaceResp.value = iface;
});
break;
case IfaceType.P2P:
ifaceCreationData.chipInfo.chip.createP2pIface(
(WifiStatus status, IWifiP2pIface iface) -> {
statusResp.value = status;
ifaceResp.value = iface;
});
break;
case IfaceType.NAN:
ifaceCreationData.chipInfo.chip.createNanIface(
(WifiStatus status, IWifiNanIface iface) -> {
statusResp.value = status;
ifaceResp.value = iface;
});
break;
}
if (statusResp.value.code != WifiStatusCode.SUCCESS) {
Log.e(TAG, "executeChipReconfiguration: failed to create interface ifaceType="
+ ifaceType + ": " + statusString(statusResp.value));
return null;
}
return ifaceResp.value;
} catch (RemoteException e) {
Log.e(TAG, "executeChipReconfiguration exception: " + e);
return null;
}
}
}
主要看里面的
WifiStatus status = ifaceCreationData.chipInfo.chip.configureChip(
ifaceCreationData.chipModeId);
这里就又走到了native
hardware/interfaces/wifi/1.2/default/wifi_chip.cpp
Return<void> WifiChip::configureChip(ChipModeId mode_id,
configureChip_cb hidl_status_cb) {
return validateAndCallWithLock(
this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::configureChipInternal, hidl_status_cb, mode_id);
}
WifiStatus WifiChip::configureChipInternal(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
ChipModeId mode_id) {
LOG(INFO) << "configureChipInternal mode: " << mode_id << ", current mode: " << current_mode_id_;
if (!isValidModeId(mode_id)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
if (mode_id == current_mode_id_) {
LOG(DEBUG) << "Already in the specified mode " << mode_id;
return createWifiStatus(WifiStatusCode::SUCCESS);
}
WifiStatus status = handleChipConfiguration(lock, mode_id);
if (status.code != WifiStatusCode::SUCCESS) {
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onChipReconfigureFailure(status).isOk()) {
LOG(ERROR)
<< "Failed to invoke onChipReconfigureFailure callback";
}
}
return status;
}
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onChipReconfigured(mode_id).isOk()) {
LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
}
}
current_mode_id_ = mode_id;
LOG(INFO) << "Configured chip in mode " << mode_id;
return status;
}
WifiStatus WifiChip::handleChipConfiguration(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
ChipModeId mode_id) {
LOG(INFO) << "handleChipConfiguration ";
// If the chip is already configured in a different mode, stop
// the legacy HAL and then start it after firmware mode change.
if (isValidModeId(current_mode_id_)) {
LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
<< " to mode " << mode_id;
invalidateAndRemoveAllIfaces();
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->stop(lock, []() {});
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to stop legacy HAL: "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
}
// Firmware mode change not needed for V2 devices.
bool success = true;
if (mode_id == kV1StaChipModeId) {
success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
} else if (mode_id == kV1ApChipModeId) {
success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
}
if (!success) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to start legacy HAL: "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
// Every time the HAL is restarted, we need to register the
// radio mode change callback.
WifiStatus status = registerRadioModeChangeCallback();
if (status.code != WifiStatusCode::SUCCESS) {
// This probably is not a critical failure?
LOG(ERROR) << "Failed to register radio mode change callback";
}
return createWifiStatus(WifiStatusCode::SUCCESS);
}
hardware/interfaces/wifi/1.2/default/wifi_legacy_hal.cpp
wifi_error WifiLegacyHal::start() {
// Ensure that we're starting in a good state.
//CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
// iface_name_to_handle_.empty() && !awaiting_event_loop_termination_);
if (is_started_) {
LOG(INFO) << "Legacy HAL already started";
return WIFI_SUCCESS;
}
LOG(INFO) << "Waiting for the driver ready";
wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
if (status == WIFI_ERROR_TIMED_OUT) {
LOG(ERROR) << "Timed out awaiting driver ready";
return status;
}
LOG(INFO) << "Starting legacy HAL";
if (!iface_tool_.SetWifiUpState(true)) {
LOG(ERROR) << "Failed to set WiFi interface up";
return WIFI_ERROR_UNKNOWN;
}
status = global_func_table_.wifi_initialize(&global_handle_);
if (status != WIFI_SUCCESS || !global_handle_) {
LOG(ERROR) << "Failed to retrieve global handle";
return status;
}
std::thread(&WifiLegacyHal::runEventLoop, this).detach();
status = retrieveIfaceHandles();
if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
LOG(ERROR) << "Failed to retrieve wlan interface handle";
return status;
}
LOG(INFO) << "Legacy HAL start complete";
is_started_ = true;
return WIFI_SUCCESS;
}
frameworks/opt/net/wifi/libwifi_system_iface/interface_tool.cpp
bool InterfaceTool::SetWifiUpState(bool request_up) {
return SetUpState(kWlan0InterfaceName, request_up);
}
bool InterfaceTool::SetUpState(const char* if_name, bool request_up) {
base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (sock.get() < 0) {
LOG(ERROR) << "Failed to open socket to set up/down state ("
<< strerror(errno) << ")";
return false;
}
struct ifreq ifr;
if (!GetIfState(if_name, sock.get(), &ifr)) {
return false; // logging done internally
}
const bool currently_up = ifr.ifr_flags & IFF_UP;
if (currently_up == request_up) {
return true;
}
if (request_up) {
ifr.ifr_flags |= IFF_UP;
} else {
ifr.ifr_flags &= ~IFF_UP;
}
if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFFLAGS, &ifr)) != 0) {
LOG(ERROR) << "Could not set interface flags for " << if_name
<< " (" << strerror(errno) << ")";
return false;
}
return true;
}
这里通过ioctl调到了kernel中,具体过程不看了,直接找到实现的位置
kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c
static int
dhd_open(struct net_device *net)
{
dhd_info_t *dhd = DHD_DEV_INFO(net);
#ifdef TOE
uint32 toe_ol;
#endif
#ifdef BCM_FD_AGGR
char iovbuf[WLC_IOCTL_SMLEN];
dbus_config_t config;
uint32 agglimit = 0;
uint32 rpc_agg = BCM_RPC_TP_DNGL_AGG_DPC; /* host aggr not enabled yet */
#endif /* BCM_FD_AGGR */
int ifidx;
int32 ret = 0;
#if defined(OOB_INTR_ONLY)
uint32 bus_type = -1;
uint32 bus_num = -1;
uint32 slot_num = -1;
wifi_adapter_info_t *adapter = NULL;
#endif
#if defined(WL_EXT_IAPSTA) && defined(ISAM_PREINIT)
int bytes_written = 0;
struct dhd_conf *conf;
#endif
if (!dhd_download_fw_on_driverload) {
if (!dhd_driver_init_done) {
DHD_ERROR(("%s: WLAN driver is not initialized\n", __FUNCTION__));
return -1;
}
}
printf("%s: Enter %p\n", __FUNCTION__, net);
DHD_MUTEX_LOCK();
/* Init wakelock */
if (!dhd_download_fw_on_driverload) {
if (!(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) {
DHD_OS_WAKE_LOCK_INIT(dhd);
dhd->dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
}
#ifdef SHOW_LOGTRACE
skb_queue_head_init(&dhd->evt_trace_queue);
if (!(dhd->dhd_state & DHD_ATTACH_LOGTRACE_INIT)) {
ret = dhd_init_logstrs_array(dhd->pub.osh, &dhd->event_data);
if (ret == BCME_OK) {
dhd_init_static_strs_array(dhd->pub.osh, &dhd->event_data,
st_str_file_path, map_file_path);
dhd_init_static_strs_array(dhd->pub.osh, &dhd->event_data,
rom_st_str_file_path, rom_map_file_path);
dhd->dhd_state |= DHD_ATTACH_LOGTRACE_INIT;
}
}
#endif /* SHOW_LOGTRACE */
}
#if defined(PREVENT_REOPEN_DURING_HANG)
/* WAR : to prevent calling dhd_open abnormally in quick succession after hang event */
if (dhd->pub.hang_was_sent == 1) {
DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
/* Force to bring down WLAN interface in case dhd_stop() is not called
* from the upper layer when HANG event is triggered.
*/
if (!dhd_download_fw_on_driverload && dhd->pub.up == 1) {
DHD_ERROR(("%s: WLAN interface is not brought down\n", __FUNCTION__));
dhd_stop(net);
} else {
return -1;
}
}
#endif /* PREVENT_REOPEN_DURING_HANG */
DHD_OS_WAKE_LOCK(&dhd->pub);
DHD_PERIM_LOCK(&dhd->pub);
dhd->pub.dongle_trap_occured = 0;
dhd->pub.hang_was_sent = 0;
dhd->pub.hang_reason = 0;
dhd->pub.iovar_timeout_occured = 0;
#ifdef PCIE_FULL_DONGLE
dhd->pub.d3ack_timeout_occured = 0;
#endif /* PCIE_FULL_DONGLE */
#ifdef DHD_LOSSLESS_ROAMING
dhd->pub.dequeue_prec_map = ALLPRIO;
#endif
#if 0
/*
* Force start if ifconfig_up gets called before START command
* We keep WEXT's wl_control_wl_start to provide backward compatibility
* This should be removed in the future
*/
ret = wl_control_wl_start(net);
if (ret != 0) {
DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
ret = -1;
goto exit;
}
#endif
ifidx = dhd_net2idx(dhd, net);
DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
if (ifidx < 0) {
DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
ret = -1;
goto exit;
}
if (!dhd->iflist[ifidx]) {
DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
ret = -1;
goto exit;
}
if (ifidx == 0) {
atomic_set(&dhd->pend_8021x_cnt, 0);
if (!dhd_download_fw_on_driverload) {
DHD_ERROR(("\n%s\n", dhd_version));
#ifdef WL_EXT_IAPSTA
wl_ext_iapsta_attach_netdev(net, ifidx, dhd->iflist[ifidx]->bssidx);
#endif
#if defined(USE_INITIAL_SHORT_DWELL_TIME)
g_first_broadcast_scan = TRUE;
#endif
#if defined(BT_OVER_SDIO)
ret = dhd_bus_get(&dhd->pub, WLAN_MODULE);
wl_android_set_wifi_on_flag(TRUE);
#else
ret = wl_android_wifi_on(net);
#endif /* BT_OVER_SDIO */
if (ret != 0) {
DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
__FUNCTION__, ret));
ret = -1;
goto exit;
}
#if defined(WL_EXT_IAPSTA) && defined(ISAM_PREINIT)
conf = dhd_get_conf(net);
if (conf) {
wl_android_ext_priv_cmd(net, conf->isam_init, 0, &bytes_written);
wl_android_ext_priv_cmd(net, conf->isam_config, 0, &bytes_written);
wl_android_ext_priv_cmd(net, conf->isam_enable, 0, &bytes_written);
}
#endif
}
#ifdef FIX_CPU_MIN_CLOCK
if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) {
dhd_init_cpufreq_fix(dhd);
dhd_fix_cpu_freq(dhd);
}
#endif /* FIX_CPU_MIN_CLOCK */
#if defined(OOB_INTR_ONLY)
if (dhd->pub.conf->dpc_cpucore >= 0) {
dhd_bus_get_ids(dhd->pub.bus, &bus_type, &bus_num, &slot_num);
adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
if (adapter) {
printf("%s: set irq affinity hit %d\n", __FUNCTION__, dhd->pub.conf->dpc_cpucore);
irq_set_affinity_hint(adapter->irq_num, cpumask_of(dhd->pub.conf->dpc_cpucore));
}
}
#endif
if (dhd->pub.busstate != DHD_BUS_DATA) {
#ifdef BCMDBUS
dhd_set_path(&dhd->pub);
DHD_MUTEX_UNLOCK();
wait_event_interruptible_timeout(dhd->adapter->status_event,
wifi_get_adapter_status(dhd->adapter, WIFI_STATUS_FW_READY),
msecs_to_jiffies(DHD_FW_READY_TIMEOUT));
DHD_MUTEX_LOCK();
if ((ret = dbus_up(dhd->pub.bus)) != 0) {
DHD_ERROR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, ret));
goto exit;
} else {
dhd->pub.busstate = DHD_BUS_DATA;
}
if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) {
DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
goto exit;
}
#else
/* try to bring up bus */
DHD_PERIM_UNLOCK(&dhd->pub);
ret = dhd_bus_start(&dhd->pub);
DHD_PERIM_LOCK(&dhd->pub);
if (ret) {
DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
ret = -1;
goto exit;
}
#endif /* !BCMDBUS */
}
#ifdef WL_EXT_IAPSTA
wl_ext_iapsta_attach_name(net, ifidx);
#endif
if (dhd_download_fw_on_driverload) {
if (dhd->pub.conf->deepsleep)
dhd_deepsleep(dhd, 0);
}
#ifdef BCM_FD_AGGR
config.config_id = DBUS_CONFIG_ID_AGGR_LIMIT;
memset(iovbuf, 0, sizeof(iovbuf));
bcm_mkiovar("rpc_dngl_agglimit", (char *)&agglimit, 4,
iovbuf, sizeof(iovbuf));
if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) {
agglimit = *(uint32 *)iovbuf;
config.aggr_param.maxrxsf = agglimit >> BCM_RPC_TP_AGG_SF_SHIFT;
config.aggr_param.maxrxsize = agglimit & BCM_RPC_TP_AGG_BYTES_MASK;
DHD_ERROR(("rpc_dngl_agglimit %x : sf_limit %d bytes_limit %d\n",
agglimit, config.aggr_param.maxrxsf, config.aggr_param.maxrxsize));
if (bcm_rpc_tp_set_config(dhd->pub.info->rpc_th, &config)) {
DHD_ERROR(("set tx/rx queue size and buffersize failed\n"));
}
} else {
DHD_ERROR(("get rpc_dngl_agglimit failed\n"));
rpc_agg &= ~BCM_RPC_TP_DNGL_AGG_DPC;
}
/* Set aggregation for TX */
bcm_rpc_tp_agg_set(dhd->pub.info->rpc_th, BCM_RPC_TP_HOST_AGG_MASK,
rpc_agg & BCM_RPC_TP_HOST_AGG_MASK);
/* Set aggregation for RX */
memset(iovbuf, 0, sizeof(iovbuf));
bcm_mkiovar("rpc_agg", (char *)&rpc_agg, sizeof(rpc_agg), iovbuf, sizeof(iovbuf));
if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) {
dhd->pub.info->fdaggr = 0;
if (rpc_agg & BCM_RPC_TP_HOST_AGG_MASK)
dhd->pub.info->fdaggr |= BCM_FDAGGR_H2D_ENABLED;
if (rpc_agg & BCM_RPC_TP_DNGL_AGG_MASK)
dhd->pub.info->fdaggr |= BCM_FDAGGR_D2H_ENABLED;
} else {
DHD_ERROR(("%s(): Setting RX aggregation failed %d\n", __FUNCTION__, ret));
}
#endif /* BCM_FD_AGGR */
#ifdef BT_OVER_SDIO
if (dhd->pub.is_bt_recovery_required) {
DHD_ERROR(("%s: Send Hang Notification 2 to BT\n", __FUNCTION__));
bcmsdh_btsdio_process_dhd_hang_notification(TRUE);
}
dhd->pub.is_bt_recovery_required = FALSE;
#endif
/* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */
memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
#ifdef TOE
/* Get current TOE mode from dongle */
if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) {
dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
} else {
dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
}
#endif /* TOE */
#if defined(DHD_LB_RXP)
__skb_queue_head_init(&dhd->rx_pend_queue);
if (dhd->rx_napi_netdev == NULL) {
dhd->rx_napi_netdev = dhd->iflist[ifidx]->net;
memset(&dhd->rx_napi_struct, 0, sizeof(struct napi_struct));
netif_napi_add(dhd->rx_napi_netdev, &dhd->rx_napi_struct,
dhd_napi_poll, dhd_napi_weight);
DHD_INFO(("%s napi<%p> enabled ifp->net<%p,%s>\n",
__FUNCTION__, &dhd->rx_napi_struct, net, net->name));
napi_enable(&dhd->rx_napi_struct);
DHD_INFO(("%s load balance init rx_napi_struct\n", __FUNCTION__));
skb_queue_head_init(&dhd->rx_napi_queue);
} /* rx_napi_netdev == NULL */
#endif /* DHD_LB_RXP */
#if defined(DHD_LB_TXP)
/* Use the variant that uses locks */
skb_queue_head_init(&dhd->tx_pend_queue);
#endif /* DHD_LB_TXP */
#if defined(WL_CFG80211)
if (unlikely(wl_cfg80211_up(net))) {
DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
ret = -1;
goto exit;
}
if (!dhd_download_fw_on_driverload) {
#ifdef ARP_OFFLOAD_SUPPORT
dhd->pend_ipaddr = 0;
if (!dhd_inetaddr_notifier_registered) {
dhd_inetaddr_notifier_registered = TRUE;
register_inetaddr_notifier(&dhd_inetaddr_notifier);
}
#endif /* ARP_OFFLOAD_SUPPORT */
#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT)
if (!dhd_inet6addr_notifier_registered) {
dhd_inet6addr_notifier_registered = TRUE;
register_inet6addr_notifier(&dhd_inet6addr_notifier);
}
#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */
}
argos_register_notifier_init(net);
#if defined(NUM_SCB_MAX_PROBE)
dhd_set_scb_probe(&dhd->pub);
#endif /* NUM_SCB_MAX_PROBE */
#endif /* WL_CFG80211 */
}
/* Allow transmit calls */
netif_start_queue(net);
dhd->pub.up = 1;
OLD_MOD_INC_USE_COUNT;
#ifdef BCMDBGFS
dhd_dbgfs_init(&dhd->pub);
#endif
exit:
if (ret) {
dhd_stop(net);
}
DHD_PERIM_UNLOCK(&dhd->pub);
DHD_OS_WAKE_UNLOCK(&dhd->pub);
DHD_MUTEX_UNLOCK();
printf("%s: Exit ret=%d\n", __FUNCTION__, ret);
return ret;
}
这个方法是真的长,到此就找到了上面热点打不开报错的位置:
if (!dhd_download_fw_on_driverload) {
if (!dhd_driver_init_done) {
DHD_ERROR(("%s: WLAN driver is not initialized\n", __FUNCTION__));
return -1;
}
}
那么dhd_driver_init_done是在什么时候被设置为true的呢,看这个类里面的dhd_module_init方法,也就是说在第7点的startHal()方法;流程中被置为true的,而之前有分析了,startHal()成功的判断条件是/proc/net/dev节点中存在wlan0,那么什么时候开始这个判断成立的呢,看dhd_module_init(void)的register_reboot_notifier(&dhd_reboot_notifier),在这个方法流程中就会初始化wlan0,那么这就导致了,同步问题,wlan0虽然初始化完成了,但dhd_driver_init_done还未被设置,导致上面的报错
解决办法
为 **dhd_module_init(void)和dhd_open(struct net_device *net)**这两个方法添加互斥锁,已解决同步问题,如下:
DEFINE_MUTEX(_wlan_init_mutex_lock_);
#define WLAN_MUTEX_LOCK() \
do { \
if (mutex_is_locked(&_wlan_init_mutex_lock_) == 0) { \
printf("%s : no wlan mutex held. set lock\n", __FUNCTION__); \
} else { \
printf("%s : wlan mutex is locked!. wait for unlocking\n", __FUNCTION__); \
} \
mutex_lock(&_wlan_init_mutex_lock_); \
} while (0)
#define WLAN_MUTEX_UNLOCK() \
do { \
mutex_unlock(&_wlan_init_mutex_lock_); \
printf("%s : the wlan lock is released.\n", __FUNCTION__); \
} while (0)
if (!dhd_download_fw_on_driverload) {
WLAN_MUTEX_LOCK();
if (!dhd_driver_init_done) {
DHD_ERROR(("%s: WLAN driver is not initialized\n", __FUNCTION__));
WLAN_MUTEX_UNLOCK();
return -1;
}else{
WLAN_MUTEX_UNLOCK();
}
}
static int
dhd_module_init(void)
{
int err;
int retry = 0;
WLAN_MUTEX_LOCK();
printf("%s: in %s\n", __FUNCTION__, dhd_version);
DHD_PERIM_RADIO_INIT();
............
............
............
printf("%s: Exit err=%d\n", __FUNCTION__, err);
WLAN_MUTEX_UNLOCK();
return err;
}