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

  • Post author:
  • Post category:其他




[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. 要求供应商优化卸载驱动耗时;



版权声明:本文为u014175785原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。