Merge changes from topic 'hal_firmware_reload'

* changes:
  wifi: Implement chip mode combinations
  wifi: Split out initialize and  start in WifiLegacyHal
  wifi: Add firmware mode controller
This commit is contained in:
Treehugger Robot
2016-12-08 23:36:24 +00:00
committed by Gerrit Code Review
9 changed files with 332 additions and 64 deletions

View File

@@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \
wifi_ap_iface.cpp \
wifi_chip.cpp \
wifi_legacy_hal.cpp \
wifi_mode_controller.cpp \
wifi_nan_iface.cpp \
wifi_p2p_iface.cpp \
wifi_rtt_controller.cpp \
@@ -39,6 +40,7 @@ LOCAL_SHARED_LIBRARIES := \
liblog \
libnl \
libutils \
libwifi-hal \
libwifi-system
LOCAL_WHOLE_STATIC_LIBRARIES := $(LIB_WIFI_HAL)
LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc

View File

@@ -34,6 +34,7 @@ using hidl_return_util::validateAndCall;
Wifi::Wifi()
: legacy_hal_(new legacy_hal::WifiLegacyHal()),
mode_controller_(new mode_controller::WifiModeController()),
run_state_(RunState::STOPPED) {}
bool Wifi::isValid() {
@@ -96,25 +97,29 @@ WifiStatus Wifi::startInternal() {
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
"HAL is stopping");
}
LOG(INFO) << "Starting HAL";
legacy_hal::wifi_error legacy_status = legacy_hal_->start();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to start Wifi HAL: "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status,
"Failed to start HAL");
WifiStatus wifi_status = initializeLegacyHal();
if (wifi_status.code == WifiStatusCode::SUCCESS) {
// Create the chip instance once the HAL is started.
chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_);
run_state_ = RunState::STARTED;
for (const auto& callback : event_callbacks_) {
if (!callback->onStart().getStatus().isOk()) {
LOG(ERROR) << "Failed to invoke onStart callback";
};
}
for (const auto& callback : event_callbacks_) {
if (!callback->onFailure(wifi_status).getStatus().isOk()) {
LOG(ERROR) << "Failed to invoke onFailure callback";
}
}
} else {
for (const auto& callback : event_callbacks_) {
if (!callback->onFailure(wifi_status).getStatus().isOk()) {
LOG(ERROR) << "Failed to invoke onFailure callback";
}
}
}
// Create the chip instance once the HAL is started.
chip_ = new WifiChip(kChipId, legacy_hal_);
run_state_ = RunState::STARTED;
for (const auto& callback : event_callbacks_) {
if (!callback->onStart().getStatus().isOk()) {
LOG(ERROR) << "Failed to invoke onStart callback";
};
}
return createWifiStatus(WifiStatusCode::SUCCESS);
return wifi_status;
}
WifiStatus Wifi::stopInternal() {
@@ -124,34 +129,21 @@ WifiStatus Wifi::stopInternal() {
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
"HAL is stopping");
}
LOG(INFO) << "Stopping HAL";
run_state_ = RunState::STOPPING;
const auto on_complete_callback_ = [&]() {
if (chip_.get()) {
chip_->invalidate();
}
chip_.clear();
run_state_ = RunState::STOPPED;
WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController();
if (wifi_status.code == WifiStatusCode::SUCCESS) {
for (const auto& callback : event_callbacks_) {
if (!callback->onStop().getStatus().isOk()) {
LOG(ERROR) << "Failed to invoke onStop callback";
};
}
};
legacy_hal::wifi_error legacy_status =
legacy_hal_->stop(on_complete_callback_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to stop Wifi HAL: "
<< legacyErrorToString(legacy_status);
WifiStatus wifi_status =
createWifiStatusFromLegacyError(legacy_status, "Failed to stop HAL");
} else {
for (const auto& callback : event_callbacks_) {
callback->onFailure(wifi_status);
if (!callback->onFailure(wifi_status).getStatus().isOk()) {
LOG(ERROR) << "Failed to invoke onFailure callback";
}
}
return wifi_status;
}
return createWifiStatus(WifiStatusCode::SUCCESS);
return wifi_status;
}
std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
@@ -171,6 +163,41 @@ std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
}
return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
}
WifiStatus Wifi::initializeLegacyHal() {
LOG(INFO) << "Initializing legacy HAL";
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);
}
WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController() {
LOG(INFO) << "Stopping legacy HAL";
run_state_ = RunState::STOPPING;
const auto on_complete_callback_ = [&]() {
if (chip_.get()) {
chip_->invalidate();
}
chip_.clear();
run_state_ = RunState::STOPPED;
};
legacy_hal::wifi_error legacy_status =
legacy_hal_->stop(on_complete_callback_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to stop legacy HAL: "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
if (!mode_controller_->deinitialize()) {
LOG(ERROR) << "Failed to deinitialize firmware mode controller";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return createWifiStatus(WifiStatusCode::SUCCESS);
}
} // namespace implementation
} // namespace V1_0
} // namespace wifi

View File

@@ -25,6 +25,7 @@
#include "wifi_chip.h"
#include "wifi_legacy_hal.h"
#include "wifi_mode_controller.h"
namespace android {
namespace hardware {
@@ -62,9 +63,13 @@ class Wifi : public IWifi {
std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
WifiStatus initializeLegacyHal();
WifiStatus stopLegacyHalAndDeinitializeModeController();
// Instance is created in this root level |IWifi| HIDL interface object
// and shared with all the child HIDL interface objects.
std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
RunState run_state_;
std::vector<sp<IWifiEventCallback>> event_callbacks_;
sp<WifiChip> chip_;

View File

@@ -24,6 +24,12 @@ namespace {
using android::sp;
using android::hardware::hidl_vec;
using android::hardware::hidl_string;
using android::hardware::wifi::V1_0::IWifiChip;
using android::hardware::wifi::V1_0::IfaceType;
constexpr uint32_t kStaChipModeId = 0;
constexpr uint32_t kApChipModeId = 1;
constexpr uint32_t kInvalidModeId = UINT32_MAX;
template <typename Iface>
void invalidateAndClear(sp<Iface>& iface) {
@@ -41,9 +47,15 @@ namespace V1_0 {
namespace implementation {
using hidl_return_util::validateAndCall;
WifiChip::WifiChip(ChipId chip_id,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
: chip_id_(chip_id), legacy_hal_(legacy_hal), is_valid_(true) {}
WifiChip::WifiChip(
ChipId chip_id,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<mode_controller::WifiModeController> mode_controller)
: chip_id_(chip_id),
legacy_hal_(legacy_hal),
mode_controller_(mode_controller),
is_valid_(true),
current_mode_id_(kInvalidModeId) {}
void WifiChip::invalidate() {
invalidateAndRemoveAllIfaces();
@@ -301,19 +313,84 @@ std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
WifiChip::getAvailableModesInternal() {
// TODO add implementation
return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
// The chip combination supported for current devices is fixed for now with
// 2 separate modes of operation:
// Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN iface operations
// concurrently.
// Mode 2 (AP mode): Will support 1 AP iface operations.
// TODO (b/32997844): Read this from some device specific flags in the
// makefile.
// STA mode iface combinations.
const IWifiChip::ChipIfaceCombinationLimit
sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
const IWifiChip::ChipIfaceCombinationLimit
sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN},
1};
const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = {
{sta_chip_iface_combination_limit_1, sta_chip_iface_combination_limit_2}};
const IWifiChip::ChipMode sta_chip_mode = {kStaChipModeId,
{sta_chip_iface_combination}};
// AP mode iface combinations.
const IWifiChip::ChipIfaceCombinationLimit ap_chip_iface_combination_limit = {
{IfaceType::AP}, 1};
const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = {
{ap_chip_iface_combination_limit}};
const IWifiChip::ChipMode ap_chip_mode = {kApChipModeId,
{ap_chip_iface_combination}};
return {createWifiStatus(WifiStatusCode::SUCCESS),
{sta_chip_mode, ap_chip_mode}};
}
WifiStatus WifiChip::configureChipInternal(uint32_t /* mode_id */) {
invalidateAndRemoveAllIfaces();
// TODO add implementation
WifiStatus WifiChip::configureChipInternal(uint32_t mode_id) {
if (mode_id != kStaChipModeId && mode_id != kApChipModeId) {
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);
}
// If the chip is already configured in a different mode, stop
// the legacy HAL and then start it after firmware mode change.
if (current_mode_id_ != kInvalidModeId) {
invalidateAndRemoveAllIfaces();
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stop([]() {});
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to stop legacy HAL: "
<< legacyErrorToString(legacy_status);
// TODO(b/33038823): Need to invoke onChipReconfigureFailure()
return createWifiStatusFromLegacyError(legacy_status);
}
}
bool success;
if (mode_id == kStaChipModeId) {
success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
} else {
success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
}
if (!success) {
// TODO(b/33038823): Need to invoke onChipReconfigureFailure()
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);
// TODO(b/33038823): Need to invoke onChipReconfigureFailure()
return createWifiStatusFromLegacyError(legacy_status);
}
for (const auto& callback : event_callbacks_) {
callback->onChipReconfigured(mode_id);
}
current_mode_id_ = mode_id;
return createWifiStatus(WifiStatusCode::SUCCESS);
}
std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
// TODO add implementation
return {createWifiStatus(WifiStatusCode::SUCCESS), 0};
if (current_mode_id_ == kInvalidModeId) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
current_mode_id_};
}
return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
}
std::pair<WifiStatus, IWifiChip::ChipDebugInfo>

View File

@@ -24,6 +24,7 @@
#include "wifi_ap_iface.h"
#include "wifi_legacy_hal.h"
#include "wifi_mode_controller.h"
#include "wifi_nan_iface.h"
#include "wifi_p2p_iface.h"
#include "wifi_rtt_controller.h"
@@ -42,8 +43,10 @@ namespace implementation {
*/
class WifiChip : public IWifiChip {
public:
WifiChip(ChipId chip_id,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
WifiChip(
ChipId chip_id,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<mode_controller::WifiModeController> mode_controller);
// HIDL does not provide a built-in mechanism to let the server invalidate
// a HIDL interface object after creation. If any client process holds onto
// a reference to the object in their context, any method calls on that
@@ -156,6 +159,7 @@ class WifiChip : public IWifiChip {
ChipId chip_id_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
std::vector<sp<IWifiChipEventCallback>> event_callbacks_;
sp<WifiApIface> ap_iface_;
sp<WifiNanIface> nan_iface_;
@@ -163,6 +167,7 @@ class WifiChip : public IWifiChip {
sp<WifiStaIface> sta_iface_;
std::vector<sp<WifiRttController>> rtt_controllers_;
bool is_valid_;
uint32_t current_mode_id_;
DISALLOW_COPY_AND_ASSIGN(WifiChip);
};

View File

@@ -18,10 +18,11 @@
#include <android-base/logging.h>
#include <cutils/properties.h>
#include <wifi_system/interface_tool.h>
#include "wifi_legacy_hal.h"
using android::wifi_system::InterfaceTool;
namespace android {
namespace hardware {
namespace wifi {
@@ -241,12 +242,7 @@ WifiLegacyHal::WifiLegacyHal()
wlan_interface_handle_(nullptr),
awaiting_event_loop_termination_(false) {}
wifi_error WifiLegacyHal::start() {
// Ensure that we're starting in a good state.
CHECK(!global_handle_ && !wlan_interface_handle_ &&
!awaiting_event_loop_termination_);
android::wifi_system::InterfaceTool if_tool;
wifi_error WifiLegacyHal::initialize() {
// 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.
wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
@@ -254,13 +250,19 @@ wifi_error WifiLegacyHal::start() {
LOG(ERROR) << "Failed to initialize legacy hal function table";
return WIFI_ERROR_UNKNOWN;
}
if (!if_tool.SetWifiUpState(true)) {
return WIFI_SUCCESS;
}
wifi_error WifiLegacyHal::start() {
// Ensure that we're starting in a good state.
CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
!wlan_interface_handle_ && !awaiting_event_loop_termination_);
if (!iface_tool_.SetWifiUpState(true)) {
LOG(ERROR) << "Failed to set WiFi interface up";
return WIFI_ERROR_UNKNOWN;
}
LOG(INFO) << "Starting legacy HAL";
status = global_func_table_.wifi_initialize(&global_handle_);
wifi_error status = global_func_table_.wifi_initialize(&global_handle_);
if (status != WIFI_SUCCESS || !global_handle_) {
LOG(ERROR) << "Failed to retrieve global handle";
return status;
@@ -280,10 +282,11 @@ wifi_error WifiLegacyHal::stop(
LOG(INFO) << "Stopping legacy HAL";
on_stop_complete_internal_callback = [&](wifi_handle handle) {
CHECK_EQ(global_handle_, handle) << "Handle mismatch";
on_stop_complete_user_callback();
// Invalidate all the internal pointers now that the HAL is
// stopped.
invalidate();
iface_tool_.SetWifiUpState(false);
on_stop_complete_user_callback();
};
awaiting_event_loop_termination_ = true;
global_func_table_.wifi_cleanup(global_handle_, onStopComplete);
@@ -974,8 +977,6 @@ void WifiLegacyHal::runEventLoop() {
}
LOG(VERBOSE) << "Legacy HAL event loop terminated";
awaiting_event_loop_termination_ = false;
android::wifi_system::InterfaceTool if_tool;
if_tool.SetWifiUpState(false);
}
std::pair<wifi_error, std::vector<wifi_cached_scan_results>>

View File

@@ -21,6 +21,8 @@
#include <thread>
#include <vector>
#include <wifi_system/interface_tool.h>
namespace android {
namespace hardware {
namespace wifi {
@@ -125,7 +127,9 @@ class WifiLegacyHal {
std::string getP2pIfaceName();
std::string getStaIfaceName();
// Initialize the legacy HAL and start the event looper thread.
// Initialize the legacy HAL function table.
wifi_error initialize();
// Start the legacy HAL and the event looper thread.
wifi_error start();
// Deinitialize the legacy HAL and stop the event looper thread.
wifi_error stop(const std::function<void()>& on_complete_callback);
@@ -245,6 +249,7 @@ class WifiLegacyHal {
wifi_interface_handle wlan_interface_handle_;
// Flag to indicate if we have initiated the cleanup of legacy HAL.
bool awaiting_event_loop_termination_;
wifi_system::InterfaceTool iface_tool_;
};
} // namespace legacy_hal

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <private/android_filesystem_config.h>
#include "wifi_mode_controller.h"
using android::hardware::wifi::V1_0::IfaceType;
using android::wifi_hal::DriverTool;
namespace {
int convertIfaceTypeToFirmwareMode(IfaceType type) {
int mode;
switch (type) {
case IfaceType::AP:
mode = DriverTool::kFirmwareModeAp;
break;
case IfaceType::P2P:
mode = DriverTool::kFirmwareModeP2p;
break;
case IfaceType::NAN:
// NAN is exposed in STA mode currently.
mode = DriverTool::kFirmwareModeSta;
break;
case IfaceType::STA:
mode = DriverTool::kFirmwareModeSta;
break;
}
return mode;
}
}
namespace android {
namespace hardware {
namespace wifi {
namespace V1_0 {
namespace implementation {
namespace mode_controller {
WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
return driver_tool_->IsFirmwareModeChangeNeeded(
convertIfaceTypeToFirmwareMode(type));
}
bool WifiModeController::changeFirmwareMode(IfaceType type) {
if (!driver_tool_->LoadDriver()) {
LOG(ERROR) << "Failed to load WiFi driver";
return false;
}
if (!driver_tool_->IsFirmwareModeChangeNeeded(
convertIfaceTypeToFirmwareMode(type))) {
LOG(ERROR) << "Failed to change firmware mode";
return false;
}
return true;
}
bool WifiModeController::deinitialize() {
if (!driver_tool_->UnloadDriver()) {
LOG(ERROR) << "Failed to unload WiFi driver";
return false;
}
return true;
}
} // namespace mode_controller
} // namespace implementation
} // namespace V1_0
} // namespace wifi
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WIFI_MODE_CONTROLLER_H_
#define WIFI_MODE_CONTROLLER_H_
#include <wifi_hal/driver_tool.h>
#include <android/hardware/wifi/1.0/IWifi.h>
namespace android {
namespace hardware {
namespace wifi {
namespace V1_0 {
namespace implementation {
namespace mode_controller {
/**
* Class that encapsulates all firmware mode configuration.
* This class will perform the necessary firmware reloads to put the chip in the
* required state (essentially a wrapper over DriverTool).
*/
class WifiModeController {
public:
WifiModeController();
// Checks if a firmware mode change is necessary to support the specified
// iface type operations.
bool isFirmwareModeChangeNeeded(IfaceType type);
// Change the firmware mode to support the specified iface type operations.
bool changeFirmwareMode(IfaceType type);
// Unload the driver. This should be invoked whenever |IWifi.stop()| is
// invoked.
bool deinitialize();
private:
std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
};
} // namespace mode_controller
} // namespace implementation
} // namespace V1_0
} // namespace wifi
} // namespace hardware
} // namespace android
#endif // WIFI_MODE_CONTROLLER_H_