[Android][WIFI]关闭WLAN耗时分析

[Android][WIFI]关闭WLAN耗时分析

前言

背景

引发这个思考,是由于一个现象:

  1. 在热点打开的时候,关闭WLAN耗时约为1s;
  2. 在热点关闭后,再关闭WLAN,耗时在2s以上;

这么一个一致性很差的现象,确实很难让人理解,于是翻开之前的流程图,开始了梳理之路;

梳理流程

先放上之前梳理处的,关闭WLAN时的流程图:
在这里插入图片描述
其中,在WifiNative.stopHalAndWificondIfNecessary()处,实际上除了WificondControl.tearDownInterfaces(),还有一个WifiVendorHal.stopVendorHal()

//WifiNative.java
/** Helper method invoked to stop HAL if there are no more ifaces */
private void stopHalAndWificondIfNecessary() {
    synchronized (mLock) {
        /*
         * 此时STA的iface已经删除,因此如果热点也是关闭状态
         * 那么此处mIfaceMgr.hasAnyIface()返回为false,取非后为true
         */
        if (!mIfaceMgr.hasAnyIface()) {
            if (!mWificondControl.tearDownInterfaces()) {
                Log.e(TAG, "Failed to teardown ifaces from wificond");
            }
            //由于已经没有热点与STA的iface,此处会通知IWifi HAL进行一些反初始化(清理)操作
            if (mWifiVendorHal.isVendorHalSupported()) {
                mWifiVendorHal.stopVendorHal();
            } else {
                Log.i(TAG, "Vendor Hal not supported, ignoring stop.");
            }
        }
    }
}
//WifiVendorHal.java
/**
 * Stops the HAL
 */
public void stopVendorHal() {
    synchronized (sLock) {
        mHalDeviceManager.stop();
        clearState();
        mLog.info("Vendor Hal stopped").flush();
    }
}
//HalDeviceManager.java
/**
 * Stops Wi-Fi. Will also dispatch any registeredManagerStatusCallback.onStop().
 *
 * Note: direct call to HIDL - failure is not-expected.
 */
public void stop() {
    stopWifi();
}
...
private void stopWifi() {
    if (VDBG) Log.d(TAG, "stopWifi");

    synchronized (mLock) {
        try {
            if (mWifi == null) {
                Log.w(TAG, "stopWifi called but mWifi is null!?");
            } else {
                WifiStatus status = mWifi.stop();
                if (status.code != WifiStatusCode.SUCCESS) {
                    Log.e(TAG, "Cannot stop IWifi: " + statusString(status));
                }

                // even on failure since WTF??
                teardownInternal();
            }
        } catch (RemoteException e) {
            Log.e(TAG, "stopWifi exception: " + e);
        }
    }
}

可以看到这里关键调用为IWifi.stop()
那么来到IWifi HAL这边,找到IWifi::stop()这个HIDL接口的实现:

//hardware/interfaces/wifi/1.2/default/wifi.cpp
Return<void> Wifi::stop(stop_cb hidl_status_cb) {
	//老套路,模板指向最终实现为stopInternal函数
    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
                                   &Wifi::stopInternal, hidl_status_cb);
}
...
WifiStatus Wifi::stopInternal(
    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
    if (run_state_ == RunState::STOPPED) {
        return createWifiStatus(WifiStatusCode::SUCCESS);
    } else if (run_state_ == RunState::STOPPING) {
        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
                                "HAL is stopping");
    }
    // Clear the chip object and its child objects since the HAL is now
    // stopped.
    if (chip_.get()) {
        chip_->invalidate();
        chip_.clear();
    }
    WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
    if (wifi_status.code == WifiStatusCode::SUCCESS) {
        for (const auto& callback : event_cb_handler_.getCallbacks()) {
            if (!callback->onStop().isOk()) {
                LOG(ERROR) << "Failed to invoke onStop callback";
            };
        }
        LOG(INFO) << "Wifi HAL stopped";
    } 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 stop failed";
    }
    return wifi_status;
}

通过添加时间戳日志,确定stopLegacyHalAndDeinitializeModeController函数耗时在1s以上,是导致差异的主要原因;
继续定位,确认耗时主要在stopLegacyHalAndDeinitializeModeController函数内部的mode_controller_->deinitialize()函数调用上:

WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
    run_state_ = RunState::STOPPING;
    legacy_hal::wifi_error legacy_status =
        legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
        LOG(ERROR) << "Failed to stop legacy HAL: "
                   << legacyErrorToString(legacy_status);
        return createWifiStatusFromLegacyError(legacy_status);
    }
    //耗时1s以上
    if (!mode_controller_->deinitialize()) {
        LOG(ERROR) << "Failed to deinitialize firmware mode controller";
        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
    }
    return createWifiStatus(WifiStatusCode::SUCCESS);
}
//wifi_mode_controller.cpp
bool WifiModeController::deinitialize() {
    if (!driver_tool_->UnloadDriver()) {
        LOG(ERROR) << "Failed to unload WiFi driver";
        return false;
    }
    return true;
}

此处的driver_tool_->UnloadDriver()实现在libwifi-hal模块中:

//frameworks/opt/net/wifi/libwifi_hal/driver_tool.cpp
bool DriverTool::UnloadDriver() {
  return ::wifi_unload_driver() == 0;
}

//frameworks/opt/net/wifi/libwifi_hal/wifi_hal_common.cpp
int wifi_unload_driver() {
  if (!is_wifi_driver_loaded()) {
    return 0;
  }
  usleep(200000); /* allow to finish interface down */
#ifdef WIFI_DRIVER_MODULE_PATH
  if (rmmod(DRIVER_MODULE_NAME) == 0) {
    int count = 20; /* wait at most 10 seconds for completion */
    while (count-- > 0) {
      if (!is_wifi_driver_loaded()) break;
      usleep(500000);
    }
    usleep(500000); /* allow card removal */
    if (count) {
      return 0;
    }
    return -1;
  } else
    return -1;
#else
#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
  if (is_wifi_driver_loaded()) {
    if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0) return -1;
  }
#endif
  property_set(DRIVER_PROP_NAME, "unloaded");
  return 0;
#endif
}

到这里,就一目了然了,如果定义了宏WIFI_DRIVER_MODULE_PATH,那么这里会有一个rmmod的操作,实测这一步骤耗时会在700ms以上,如果按照这里的等待机制计算,则至少会耗费1200ms;

跟进

关于为什么有的项目会定义宏WIFI_DRIVER_MODULE_PATH,有的则不会;
根据调查,是取决于项目是否在BoardConfig.mk(及其依赖)中是否声明另一个宏PRODUCT_WLAN_DRIVER_ALWAYS_LOADED

ifneq ($(PRODUCT_WLAN_DRIVER_ALWAYS_LOADED), true)

ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED), true)
WIFI_DRIVER_MODULE_PATH := "xxx"
else
WIFI_DRIVER_MODULE_PATH := "yyy"
endif
...
endif

总结

导致这一差异的主要原因,是由于热点没有关闭的情况下关闭WLAN,IWifi HAL由于还需要支持热点工作,不能将WLAN网卡驱动卸载,因此耗时较短;
而当热点关闭后,再关闭WLAN时,如果项目配置时未定义PRODUCT_WLAN_DRIVER_ALWAYS_LOADED,那么libwifi-hal模块会在此时通过调用rmmod来卸载WLAN网卡驱动,这一步骤会比较耗时;

改进计划

  1. 评估是否可以开启PRODUCT_WLAN_DRIVER_ALWAYS_LOADED
  2. wifi_unload_driver()函数里面的等待时长调整;
  3. 要求供应商优化卸载驱动耗时;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值