wifi(implementation): Add iface combo for 2018
Changes in the CL:
a) Added iface combo for 2018 using a new feature flag.
b) Added a generic algorithm to determine if an iface can be created or
not based on the iface combos supported. This is needed because we now
have to support 3 different combos (2016, 2017, 2018) in the HAL.
The current iface creation logic is hard to adapt to these 3 varying combos.
Bug: 65671875
Bug: 69863101
Test: ./hardware/interfaces/wifi/1.2/default/tests/runtests.sh
Change-Id: Iff8737843abee3d03567930e9faba775eaa82e07
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
index c4956e0..d7be38f 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -30,9 +30,14 @@
using android::hardware::wifi::V1_0::IWifiChip;
using android::sp;
-constexpr ChipModeId kStaChipModeId = 0;
-constexpr ChipModeId kApChipModeId = 1;
constexpr ChipModeId kInvalidModeId = UINT32_MAX;
+// These mode ID's should be unique (even across combo versions). Refer to
+// handleChipConfiguration() for it's usage.
+// Mode ID's for V1
+constexpr ChipModeId kV1StaChipModeId = 0;
+constexpr ChipModeId kV1ApChipModeId = 1;
+// Mode ID for V2
+constexpr ChipModeId kV2ChipModeId = 2;
template <typename Iface>
void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
@@ -110,7 +115,9 @@
feature_flags_(feature_flags),
is_valid_(true),
current_mode_id_(kInvalidModeId),
- debug_ring_buffer_cb_registered_(false) {}
+ debug_ring_buffer_cb_registered_(false) {
+ populateModes();
+}
void WifiChip::invalidate() {
invalidateAndRemoveAllIfaces();
@@ -394,43 +401,13 @@
std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
WifiChip::getAvailableModesInternal() {
- // 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 [NAN conditional on wifiHidlFeatureAware]
- // 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};
- IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2;
- if (feature_flags_.lock()->isAwareSupported()) {
- sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN},
- 1};
- } else {
- sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 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}};
+ return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
}
WifiStatus WifiChip::configureChipInternal(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
ChipModeId mode_id) {
- if (mode_id != kStaChipModeId && mode_id != kApChipModeId) {
+ if (!isValidModeId(mode_id)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
if (mode_id == current_mode_id_) {
@@ -458,7 +435,7 @@
}
std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
- if (current_mode_id_ == kInvalidModeId) {
+ if (!isValidModeId(current_mode_id_)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
current_mode_id_};
}
@@ -526,7 +503,7 @@
}
std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
- if (current_mode_id_ != kApChipModeId || !ap_ifaces_.empty()) {
+ if (!canCurrentModeSupportIfaceOfType(IfaceType::AP)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = getWlan0IfaceName();
@@ -572,24 +549,18 @@
}
std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
- // Only 1 of NAN or P2P iface can be active at a time.
- if (feature_flags_.lock()->isAwareSupported()) {
- if (current_mode_id_ != kStaChipModeId || !nan_ifaces_.empty() ||
- !p2p_ifaces_.empty()) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- std::string ifname = getWlan0IfaceName();
- sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_);
- nan_ifaces_.push_back(iface);
- for (const auto& callback : event_cb_handler_.getCallbacks()) {
- if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
- LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
- }
- }
- return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
- } else {
+ if (!canCurrentModeSupportIfaceOfType(IfaceType::NAN)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
+ std::string ifname = getWlan0IfaceName();
+ sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_);
+ nan_ifaces_.push_back(iface);
+ for (const auto& callback : event_cb_handler_.getCallbacks()) {
+ if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
+ LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+ }
+ }
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
}
std::pair<WifiStatus, std::vector<hidl_string>>
@@ -624,9 +595,7 @@
}
std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
- // Only 1 of NAN or P2P iface can be active at a time.
- if (current_mode_id_ != kStaChipModeId || !p2p_ifaces_.empty() ||
- !nan_ifaces_.empty()) {
+ if (!canCurrentModeSupportIfaceOfType(IfaceType::P2P)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = getP2pIfaceName();
@@ -672,7 +641,7 @@
}
std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
- if (current_mode_id_ != kStaChipModeId || !sta_ifaces_.empty()) {
+ if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = getWlan0IfaceName();
@@ -842,7 +811,7 @@
ChipModeId mode_id) {
// 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) {
+ if (isValidModeId(current_mode_id_)) {
LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
<< " to mode " << mode_id;
invalidateAndRemoveAllIfaces();
@@ -854,10 +823,11 @@
return createWifiStatusFromLegacyError(legacy_status);
}
}
- bool success;
- if (mode_id == kStaChipModeId) {
+ // Firmware mode change not needed for V2 devices.
+ bool success = true;
+ if (mode_id == kV1StaChipModeId) {
success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
- } else {
+ } else if (mode_id == kV1ApChipModeId) {
success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
}
if (!success) {
@@ -912,6 +882,185 @@
return createWifiStatusFromLegacyError(legacy_status);
}
+void WifiChip::populateModes() {
+ // The chip combination supported for current devices is fixed.
+ // They can be one of the following based on device features:
+ // a) 2 separate modes of operation with 1 interface combination each:
+ // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN(optional)
+ // concurrent iface operations.
+ // Mode 2 (AP mode): Will support 1 AP iface operation.
+ //
+ // b) 1 mode of operation with 2 interface combinations
+ // (conditional on isDualInterfaceSupported()):
+ // Interface Combination 1: Will support 1 STA and 1 P2P or NAN(optional)
+ // concurrent iface operations.
+ // Interface Combination 2: Will support 1 STA and 1 STA or AP concurrent
+ // iface operations.
+ // If Aware is enabled (conditional on isAwareSupported()), the iface
+ // combination will be modified to support either P2P or NAN in place of
+ // just P2P.
+ if (feature_flags_.lock()->isDualInterfaceSupported()) {
+ // V2 Iface combinations for Mode Id = 2.
+ const IWifiChip::ChipIfaceCombinationLimit
+ chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
+ const IWifiChip::ChipIfaceCombinationLimit
+ chip_iface_combination_limit_2 = {{IfaceType::STA, IfaceType::AP},
+ 1};
+ IWifiChip::ChipIfaceCombinationLimit chip_iface_combination_limit_3;
+ if (feature_flags_.lock()->isAwareSupported()) {
+ chip_iface_combination_limit_3 = {{IfaceType::P2P, IfaceType::NAN},
+ 1};
+ } else {
+ chip_iface_combination_limit_3 = {{IfaceType::P2P}, 1};
+ }
+ const IWifiChip::ChipIfaceCombination chip_iface_combination_1 = {
+ {chip_iface_combination_limit_1, chip_iface_combination_limit_2}};
+ const IWifiChip::ChipIfaceCombination chip_iface_combination_2 = {
+ {chip_iface_combination_limit_1, chip_iface_combination_limit_3}};
+ const IWifiChip::ChipMode chip_mode = {
+ kV2ChipModeId,
+ {chip_iface_combination_1, chip_iface_combination_2}};
+ modes_ = {chip_mode};
+ } else {
+ // V1 Iface combinations for Mode Id = 0. (STA Mode)
+ const IWifiChip::ChipIfaceCombinationLimit
+ sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
+ IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2;
+ if (feature_flags_.lock()->isAwareSupported()) {
+ sta_chip_iface_combination_limit_2 = {
+ {IfaceType::P2P, IfaceType::NAN}, 1};
+ } else {
+ sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 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 = {
+ kV1StaChipModeId, {sta_chip_iface_combination}};
+ // Iface combinations for Mode Id = 1. (AP Mode)
+ 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 = {kV1ApChipModeId,
+ {ap_chip_iface_combination}};
+ modes_ = {sta_chip_mode, ap_chip_mode};
+ }
+}
+
+std::vector<IWifiChip::ChipIfaceCombination>
+WifiChip::getCurrentModeIfaceCombinations() {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return {};
+ }
+ for (const auto& mode : modes_) {
+ if (mode.id == current_mode_id_) {
+ return mode.availableCombinations;
+ }
+ }
+ CHECK(0) << "Expected to find iface combinations for current mode!";
+ return {};
+}
+
+// Returns a map indexed by IfaceType with the number of ifaces currently
+// created of the corresponding type.
+std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
+ std::map<IfaceType, size_t> iface_counts;
+ iface_counts[IfaceType::AP] = ap_ifaces_.size();
+ iface_counts[IfaceType::NAN] = nan_ifaces_.size();
+ iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
+ iface_counts[IfaceType::STA] = sta_ifaces_.size();
+ return iface_counts;
+}
+
+// This expands the provided iface combinations to a more parseable
+// form. Returns a vector of available combinations possible with the number
+// of ifaces of each type in the combination.
+// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
+std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
+ const IWifiChip::ChipIfaceCombination& combination) {
+ uint32_t num_expanded_combos = 1;
+ for (const auto& limit : combination.limits) {
+ for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+ num_expanded_combos *= limit.types.size();
+ }
+ }
+
+ // Allocate the vector of expanded combos and reset all iface counts to 0
+ // in each combo.
+ std::vector<std::map<IfaceType, size_t>> expanded_combos;
+ expanded_combos.resize(num_expanded_combos);
+ for (auto& expanded_combo : expanded_combos) {
+ for (const auto type :
+ {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+ expanded_combo[type] = 0;
+ }
+ }
+ uint32_t span = num_expanded_combos;
+ for (const auto& limit : combination.limits) {
+ for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+ span /= limit.types.size();
+ for (uint32_t k = 0; k < num_expanded_combos; ++k) {
+ const auto iface_type =
+ limit.types[(k / span) % limit.types.size()];
+ expanded_combos[k][iface_type]++;
+ }
+ }
+ }
+ return expanded_combos;
+}
+
+bool WifiChip::canExpandedIfaceCombinationSupportIfaceOfType(
+ const std::map<IfaceType, size_t>& combo, IfaceType requested_type) {
+ const auto current_combo = getCurrentIfaceCombination();
+
+ // Check if we have space for 1 more iface of |type| in this combo
+ for (const auto type :
+ {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+ size_t num_ifaces_needed = current_combo.at(type);
+ if (type == requested_type) {
+ num_ifaces_needed++;
+ }
+ size_t num_ifaces_allowed = combo.at(type);
+ if (num_ifaces_needed > num_ifaces_allowed) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+// ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType type) {
+ if (!isValidModeId(current_mode_id_)) {
+ LOG(ERROR) << "Chip not configured in a mode yet";
+ return false;
+ }
+ const auto combinations = getCurrentModeIfaceCombinations();
+ for (const auto& combination : combinations) {
+ const auto expanded_combos = expandIfaceCombinations(combination);
+ for (const auto& expanded_combo : expanded_combos) {
+ if (canExpandedIfaceCombinationSupportIfaceOfType(expanded_combo,
+ type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool WifiChip::isValidModeId(ChipModeId mode_id) {
+ for (const auto& mode : modes_) {
+ if (mode.id == mode_id) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace implementation
} // namespace V1_2
} // namespace wifi