Files
hardware_interfaces/wifi/aidl/default/wifi_chip.cpp
Les Lee b5d73ee5ce wifi: rename mode 'ON' to 'VOICE'.
To improve clarity and accommodate future functionalities,
we should rename the existing 'ON' mode to 'VOICE'.
This change establishes 'VOICE' as the fundamental mode for VOIP operations.
Additionally, it paves the way for adding future modes, such as 'VOICE_VIDEO',
as the system evolves.

Bug: 295885471
Test: TH

Change-Id: Ie3b54f02cf3c73b5a9c2a805ec36703dfd541666
2023-12-07 06:08:57 +00:00

1943 lines
83 KiB
C++

/*
* Copyright (C) 2022 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 "wifi_chip.h"
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <fcntl.h>
#include <hardware_legacy/wifi_hal.h>
#include <net/if.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include "aidl_return_util.h"
#include "aidl_struct_util.h"
#include "wifi_legacy_hal.h"
#include "wifi_status_util.h"
#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
namespace {
using android::base::unique_fd;
constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
constexpr uint32_t kMaxRingBufferFileNum = 20;
constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
constexpr unsigned kMaxWlanIfaces = 5;
constexpr char kApBridgeIfacePrefix[] = "ap_br_";
template <typename Iface>
void invalidateAndClear(std::vector<std::shared_ptr<Iface>>& ifaces, std::shared_ptr<Iface> iface) {
iface->invalidate();
ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), ifaces.end());
}
template <typename Iface>
void invalidateAndClearAll(std::vector<std::shared_ptr<Iface>>& ifaces) {
for (const auto& iface : ifaces) {
iface->invalidate();
}
ifaces.clear();
}
template <typename Iface>
std::vector<std::string> getNames(std::vector<std::shared_ptr<Iface>>& ifaces) {
std::vector<std::string> names;
for (const auto& iface : ifaces) {
names.emplace_back(iface->getName());
}
return names;
}
template <typename Iface>
std::shared_ptr<Iface> findUsingName(std::vector<std::shared_ptr<Iface>>& ifaces,
const std::string& name) {
std::vector<std::string> names;
for (const auto& iface : ifaces) {
if (name == iface->getName()) {
return iface;
}
}
return nullptr;
}
std::string getWlanIfaceName(unsigned idx) {
if (idx >= kMaxWlanIfaces) {
CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
return {};
}
std::array<char, PROPERTY_VALUE_MAX> buffer;
if (idx == 0 || idx == 1) {
const char* altPropName = (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
auto res = property_get(altPropName, buffer.data(), nullptr);
if (res > 0) return buffer.data();
}
std::string propName = "wifi.interface." + std::to_string(idx);
auto res = property_get(propName.c_str(), buffer.data(), nullptr);
if (res > 0) return buffer.data();
return "wlan" + std::to_string(idx);
}
// Returns the dedicated iface name if defined.
// Returns two ifaces in bridged mode.
std::vector<std::string> getPredefinedApIfaceNames(bool is_bridged) {
std::vector<std::string> ifnames;
std::array<char, PROPERTY_VALUE_MAX> buffer;
buffer.fill(0);
if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) == 0) {
return ifnames;
}
ifnames.push_back(buffer.data());
if (is_bridged) {
buffer.fill(0);
if (property_get("ro.vendor.wifi.sap.concurrent.iface", buffer.data(), nullptr) == 0) {
return ifnames;
}
ifnames.push_back(buffer.data());
}
return ifnames;
}
std::string getPredefinedP2pIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> primaryIfaceName;
char p2pParentIfname[100];
std::string p2pDevIfName = "";
std::array<char, PROPERTY_VALUE_MAX> buffer;
property_get("wifi.direct.interface", buffer.data(), "p2p0");
if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX, strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
/* Get the p2p parent interface name from p2p device interface name set
* in property */
strlcpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX),
strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX));
if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(), nullptr) == 0) {
return buffer.data();
}
/* Check if the parent interface derived from p2p device interface name
* is active */
if (strncmp(p2pParentIfname, primaryIfaceName.data(),
strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) != 0) {
/*
* Update the predefined p2p device interface parent interface name
* with current active wlan interface
*/
p2pDevIfName += P2P_MGMT_DEVICE_PREFIX;
p2pDevIfName += primaryIfaceName.data();
LOG(INFO) << "update the p2p device interface name to " << p2pDevIfName.c_str();
return p2pDevIfName;
}
}
return buffer.data();
}
// Returns the dedicated iface name if one is defined.
std::string getPredefinedNanIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) {
return {};
}
return buffer.data();
}
void setActiveWlanIfaceNameProperty(const std::string& ifname) {
auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
if (res != 0) {
PLOG(ERROR) << "Failed to set active wlan iface name property";
}
}
// Delete files that meet either condition:
// 1. Older than a predefined time in the wifi tombstone dir.
// 2. Files in excess to a predefined amount, starting from the oldest ones
bool removeOldFilesInternal() {
time_t now = time(0);
const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(kTombstoneFolderPath), closedir);
if (!dir_dump) {
PLOG(ERROR) << "Failed to open directory";
return false;
}
struct dirent* dp;
bool success = true;
std::list<std::pair<const time_t, std::string>> valid_files;
while ((dp = readdir(dir_dump.get()))) {
if (dp->d_type != DT_REG) {
continue;
}
std::string cur_file_name(dp->d_name);
struct stat cur_file_stat;
std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
success = false;
continue;
}
const time_t cur_file_time = cur_file_stat.st_mtime;
valid_files.push_back(std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
}
valid_files.sort(); // sort the list of files by last modified time from
// small to big.
uint32_t cur_file_count = valid_files.size();
for (auto cur_file : valid_files) {
if (cur_file_count > kMaxRingBufferFileNum || cur_file.first < delete_files_before) {
if (unlink(cur_file.second.c_str()) != 0) {
PLOG(ERROR) << "Error deleting file";
success = false;
}
cur_file_count--;
} else {
break;
}
}
return success;
}
// Helper function to create a non-const char*.
std::vector<char> makeCharVec(const std::string& str) {
std::vector<char> vec(str.size() + 1);
vec.assign(str.begin(), str.end());
vec.push_back('\0');
return vec;
}
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using aidl_return_util::validateAndCall;
using aidl_return_util::validateAndCallWithLock;
WifiChip::WifiChip(int32_t chip_id, bool is_primary,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
const std::function<void(const std::string&)>& handler,
bool using_dynamic_iface_combination)
: chip_id_(chip_id),
legacy_hal_(legacy_hal),
mode_controller_(mode_controller),
iface_util_(iface_util),
is_valid_(true),
current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
modes_(feature_flags.lock()->getChipModes(is_primary)),
debug_ring_buffer_cb_registered_(false),
using_dynamic_iface_combination_(using_dynamic_iface_combination),
subsystemCallbackHandler_(handler) {
setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
}
void WifiChip::retrieveDynamicIfaceCombination() {
if (using_dynamic_iface_combination_) return;
legacy_hal::wifi_iface_concurrency_matrix legacy_matrix;
legacy_hal::wifi_error legacy_status;
std::tie(legacy_status, legacy_matrix) =
legacy_hal_.lock()->getSupportedIfaceConcurrencyMatrix();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to get SupportedIfaceCombinations matrix from legacy HAL: "
<< legacyErrorToString(legacy_status);
return;
}
IWifiChip::ChipMode aidl_chip_mode;
if (!aidl_struct_util::convertLegacyIfaceCombinationsMatrixToChipMode(legacy_matrix,
&aidl_chip_mode)) {
LOG(ERROR) << "Failed convertLegacyIfaceCombinationsMatrixToChipMode() ";
return;
}
LOG(INFO) << "Reloading iface concurrency combination from driver";
aidl_chip_mode.id = feature_flags::chip_mode_ids::kV3;
modes_.clear();
modes_.push_back(aidl_chip_mode);
using_dynamic_iface_combination_ = true;
}
std::shared_ptr<WifiChip> WifiChip::create(
int32_t chip_id, bool is_primary, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
const std::function<void(const std::string&)>& handler,
bool using_dynamic_iface_combination) {
std::shared_ptr<WifiChip> ptr = ndk::SharedRefBase::make<WifiChip>(
chip_id, is_primary, legacy_hal, mode_controller, iface_util, feature_flags, handler,
using_dynamic_iface_combination);
std::weak_ptr<WifiChip> weak_ptr_this(ptr);
ptr->setWeakPtr(weak_ptr_this);
return ptr;
}
void WifiChip::invalidate() {
if (!writeRingbufferFilesInternal()) {
LOG(ERROR) << "Error writing files to flash";
}
invalidateAndRemoveAllIfaces();
setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
legacy_hal_.reset();
event_cb_handler_.invalidate();
is_valid_ = false;
}
void WifiChip::setWeakPtr(std::weak_ptr<WifiChip> ptr) {
weak_ptr_this_ = ptr;
}
bool WifiChip::isValid() {
return is_valid_;
}
std::set<std::shared_ptr<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
return event_cb_handler_.getCallbacks();
}
ndk::ScopedAStatus WifiChip::getId(int32_t* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getIdInternal,
_aidl_return);
}
ndk::ScopedAStatus WifiChip::registerEventCallback(
const std::shared_ptr<IWifiChipEventCallback>& event_callback) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::registerEventCallbackInternal, event_callback);
}
ndk::ScopedAStatus WifiChip::getFeatureSet(int32_t* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getFeatureSetInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getAvailableModes(std::vector<IWifiChip::ChipMode>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getAvailableModesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::configureChip(int32_t in_modeId) {
return validateAndCallWithLock(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::configureChipInternal, in_modeId);
}
ndk::ScopedAStatus WifiChip::getMode(int32_t* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getModeInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::requestChipDebugInfo(IWifiChip::ChipDebugInfo* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::requestChipDebugInfoInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::requestDriverDebugDump(std::vector<uint8_t>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::requestDriverDebugDumpInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::requestFirmwareDebugDump(std::vector<uint8_t>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::requestFirmwareDebugDumpInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::createApIface(std::shared_ptr<IWifiApIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createApIfaceInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::createBridgedApIface(std::shared_ptr<IWifiApIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createBridgedApIfaceInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::createApOrBridgedApIface(
IfaceConcurrencyType in_ifaceType, const std::vector<common::OuiKeyedData>& in_vendorData,
std::shared_ptr<IWifiApIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createApOrBridgedApIfaceInternal, _aidl_return, in_ifaceType,
in_vendorData);
}
ndk::ScopedAStatus WifiChip::getApIfaceNames(std::vector<std::string>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getApIfaceNamesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getApIface(const std::string& in_ifname,
std::shared_ptr<IWifiApIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getApIfaceInternal, _aidl_return, in_ifname);
}
ndk::ScopedAStatus WifiChip::removeApIface(const std::string& in_ifname) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::removeApIfaceInternal, in_ifname);
}
ndk::ScopedAStatus WifiChip::removeIfaceInstanceFromBridgedApIface(
const std::string& in_brIfaceName, const std::string& in_ifaceInstanceName) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal, in_brIfaceName,
in_ifaceInstanceName);
}
ndk::ScopedAStatus WifiChip::createNanIface(std::shared_ptr<IWifiNanIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createNanIfaceInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getNanIfaceNames(std::vector<std::string>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getNanIfaceNamesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getNanIface(const std::string& in_ifname,
std::shared_ptr<IWifiNanIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getNanIfaceInternal, _aidl_return, in_ifname);
}
ndk::ScopedAStatus WifiChip::removeNanIface(const std::string& in_ifname) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::removeNanIfaceInternal, in_ifname);
}
ndk::ScopedAStatus WifiChip::createP2pIface(std::shared_ptr<IWifiP2pIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createP2pIfaceInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getP2pIfaceNames(std::vector<std::string>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getP2pIfaceNamesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getP2pIface(const std::string& in_ifname,
std::shared_ptr<IWifiP2pIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getP2pIfaceInternal, _aidl_return, in_ifname);
}
ndk::ScopedAStatus WifiChip::removeP2pIface(const std::string& in_ifname) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::removeP2pIfaceInternal, in_ifname);
}
ndk::ScopedAStatus WifiChip::createStaIface(std::shared_ptr<IWifiStaIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createStaIfaceInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getStaIfaceNames(std::vector<std::string>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getStaIfaceNamesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getStaIface(const std::string& in_ifname,
std::shared_ptr<IWifiStaIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getStaIfaceInternal, _aidl_return, in_ifname);
}
ndk::ScopedAStatus WifiChip::removeStaIface(const std::string& in_ifname) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::removeStaIfaceInternal, in_ifname);
}
ndk::ScopedAStatus WifiChip::createRttController(
const std::shared_ptr<IWifiStaIface>& in_boundIface,
std::shared_ptr<IWifiRttController>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createRttControllerInternal, _aidl_return, in_boundIface);
}
ndk::ScopedAStatus WifiChip::getDebugRingBuffersStatus(
std::vector<WifiDebugRingBufferStatus>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getDebugRingBuffersStatusInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::startLoggingToDebugRingBuffer(
const std::string& in_ringName, WifiDebugRingBufferVerboseLevel in_verboseLevel,
int32_t in_maxIntervalInSec, int32_t in_minDataSizeInBytes) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::startLoggingToDebugRingBufferInternal, in_ringName,
in_verboseLevel, in_maxIntervalInSec, in_minDataSizeInBytes);
}
ndk::ScopedAStatus WifiChip::forceDumpToDebugRingBuffer(const std::string& in_ringName) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::forceDumpToDebugRingBufferInternal, in_ringName);
}
ndk::ScopedAStatus WifiChip::flushRingBufferToFile() {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::flushRingBufferToFileInternal);
}
ndk::ScopedAStatus WifiChip::stopLoggingToDebugRingBuffer() {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::stopLoggingToDebugRingBufferInternal);
}
ndk::ScopedAStatus WifiChip::getDebugHostWakeReasonStats(
WifiDebugHostWakeReasonStats* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getDebugHostWakeReasonStatsInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::enableDebugErrorAlerts(bool in_enable) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::enableDebugErrorAlertsInternal, in_enable);
}
ndk::ScopedAStatus WifiChip::selectTxPowerScenario(IWifiChip::TxPowerScenario in_scenario) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::selectTxPowerScenarioInternal, in_scenario);
}
ndk::ScopedAStatus WifiChip::resetTxPowerScenario() {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::resetTxPowerScenarioInternal);
}
ndk::ScopedAStatus WifiChip::setLatencyMode(IWifiChip::LatencyMode in_mode) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::setLatencyModeInternal, in_mode);
}
binder_status_t WifiChip::dump(int fd __unused, const char**, uint32_t) {
{
std::unique_lock<std::mutex> lk(lock_t);
for (const auto& item : ringbuffer_map_) {
forceDumpToDebugRingBufferInternal(item.first);
}
// unique_lock unlocked here
}
usleep(100 * 1000); // sleep for 100 milliseconds to wait for
// ringbuffer updates.
if (!writeRingbufferFilesInternal()) {
LOG(ERROR) << "Error writing files to flash";
}
return STATUS_OK;
}
ndk::ScopedAStatus WifiChip::setMultiStaPrimaryConnection(const std::string& in_ifName) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::setMultiStaPrimaryConnectionInternal, in_ifName);
}
ndk::ScopedAStatus WifiChip::setMultiStaUseCase(IWifiChip::MultiStaUseCase in_useCase) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::setMultiStaUseCaseInternal, in_useCase);
}
ndk::ScopedAStatus WifiChip::setCoexUnsafeChannels(
const std::vector<IWifiChip::CoexUnsafeChannel>& in_unsafeChannels,
int32_t in_restrictions) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::setCoexUnsafeChannelsInternal, in_unsafeChannels,
in_restrictions);
}
ndk::ScopedAStatus WifiChip::setCountryCode(const std::array<uint8_t, 2>& in_code) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiChip::setCountryCodeInternal, in_code);
}
ndk::ScopedAStatus WifiChip::getUsableChannels(WifiBand in_band, int32_t in_ifaceModeMask,
int32_t in_filterMask,
std::vector<WifiUsableChannel>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getUsableChannelsInternal, _aidl_return, in_band,
in_ifaceModeMask, in_filterMask);
}
ndk::ScopedAStatus WifiChip::setAfcChannelAllowance(
const AfcChannelAllowance& afcChannelAllowance) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::setAfcChannelAllowanceInternal, afcChannelAllowance);
}
ndk::ScopedAStatus WifiChip::triggerSubsystemRestart() {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::triggerSubsystemRestartInternal);
}
ndk::ScopedAStatus WifiChip::getSupportedRadioCombinations(
std::vector<WifiRadioCombination>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getSupportedRadioCombinationsInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getWifiChipCapabilitiesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetwork(int32_t in_channelCategoryEnableFlag) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::enableStaChannelForPeerNetworkInternal,
in_channelCategoryEnableFlag);
}
ndk::ScopedAStatus WifiChip::setMloMode(const ChipMloMode in_mode) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::setMloModeInternal, in_mode);
}
ndk::ScopedAStatus WifiChip::setVoipMode(const VoipMode in_mode) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::setVoipModeInternal, in_mode);
}
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
invalidateAndClearAll(nan_ifaces_);
invalidateAndClearAll(p2p_ifaces_);
invalidateAndClearAll(sta_ifaces_);
// Since all the ifaces are invalid now, all RTT controller objects
// using those ifaces also need to be invalidated.
for (const auto& rtt : rtt_controllers_) {
rtt->invalidate();
}
rtt_controllers_.clear();
}
void WifiChip::invalidateAndRemoveDependencies(const std::string& removed_iface_name) {
for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
auto nan_iface = *it;
if (nan_iface->getName() == removed_iface_name) {
nan_iface->invalidate();
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::NAN_IFACE, removed_iface_name).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
}
}
it = nan_ifaces_.erase(it);
} else {
++it;
}
}
for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
auto rtt = *it;
if (rtt->getIfaceName() == removed_iface_name) {
rtt->invalidate();
it = rtt_controllers_.erase(it);
} else {
++it;
}
}
}
std::pair<int32_t, ndk::ScopedAStatus> WifiChip::getIdInternal() {
return {chip_id_, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::registerEventCallbackInternal(
const std::shared_ptr<IWifiChipEventCallback>& event_callback) {
if (!event_cb_handler_.addCallback(event_callback)) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
std::pair<int32_t, ndk::ScopedAStatus> WifiChip::getFeatureSetInternal() {
legacy_hal::wifi_error legacy_status;
uint64_t legacy_feature_set;
uint32_t legacy_logger_feature_set;
const auto ifname = getFirstActiveWlanIfaceName();
std::tie(legacy_status, legacy_feature_set) =
legacy_hal_.lock()->getSupportedFeatureSet(ifname);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {0, createWifiStatusFromLegacyError(legacy_status)};
}
std::tie(legacy_status, legacy_logger_feature_set) =
legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
// some devices don't support querying logger feature set
legacy_logger_feature_set = 0;
}
uint32_t aidl_feature_set;
if (!aidl_struct_util::convertLegacyChipFeaturesToAidl(legacy_feature_set, &aidl_feature_set)) {
return {0, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_feature_set, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<IWifiChip::ChipMode>, ndk::ScopedAStatus>
WifiChip::getAvailableModesInternal() {
return {modes_, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::configureChipInternal(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, int32_t 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 ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus status = handleChipConfiguration(lock, mode_id);
if (!status.isOk()) {
WifiStatusCode errorCode = static_cast<WifiStatusCode>(status.getServiceSpecificError());
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onChipReconfigureFailure(errorCode).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;
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(subsystemCallbackHandler_);
return status;
}
std::pair<int32_t, ndk::ScopedAStatus> WifiChip::getModeInternal() {
if (!isValidModeId(current_mode_id_)) {
return {current_mode_id_, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
return {current_mode_id_, ndk::ScopedAStatus::ok()};
}
std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> WifiChip::requestChipDebugInfoInternal() {
IWifiChip::ChipDebugInfo result;
legacy_hal::wifi_error legacy_status;
std::string driver_desc;
const auto ifname = getFirstActiveWlanIfaceName();
std::tie(legacy_status, driver_desc) = legacy_hal_.lock()->getDriverVersion(ifname);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to get driver version: " << legacyErrorToString(legacy_status);
ndk::ScopedAStatus status =
createWifiStatusFromLegacyError(legacy_status, "failed to get driver version");
return {std::move(result), std::move(status)};
}
result.driverDescription = driver_desc.c_str();
std::string firmware_desc;
std::tie(legacy_status, firmware_desc) = legacy_hal_.lock()->getFirmwareVersion(ifname);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to get firmware version: " << legacyErrorToString(legacy_status);
ndk::ScopedAStatus status =
createWifiStatusFromLegacyError(legacy_status, "failed to get firmware version");
return {std::move(result), std::move(status)};
}
result.firmwareDescription = firmware_desc.c_str();
return {std::move(result), ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> WifiChip::requestDriverDebugDumpInternal() {
legacy_hal::wifi_error legacy_status;
std::vector<uint8_t> driver_dump;
std::tie(legacy_status, driver_dump) =
legacy_hal_.lock()->requestDriverMemoryDump(getFirstActiveWlanIfaceName());
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to get driver debug dump: " << legacyErrorToString(legacy_status);
return {std::vector<uint8_t>(), createWifiStatusFromLegacyError(legacy_status)};
}
return {driver_dump, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> WifiChip::requestFirmwareDebugDumpInternal() {
legacy_hal::wifi_error legacy_status;
std::vector<uint8_t> firmware_dump;
std::tie(legacy_status, firmware_dump) =
legacy_hal_.lock()->requestFirmwareMemoryDump(getFirstActiveWlanIfaceName());
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to get firmware debug dump: " << legacyErrorToString(legacy_status);
return {std::vector<uint8_t>(), createWifiStatusFromLegacyError(legacy_status)};
}
return {firmware_dump, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
legacy_hal::wifi_error legacy_status;
legacy_status = legacy_hal_.lock()->createVirtualInterface(
apVirtIf, aidl_struct_util::convertAidlIfaceTypeToLegacy(IfaceType::AP));
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
std::vector<std::string> ap_instances;
for (auto const& it : br_ifaces_ap_instances_) {
if (it.first == ifname) {
ap_instances = it.second;
}
}
std::shared_ptr<WifiApIface> iface =
ndk::SharedRefBase::make<WifiApIface>(ifname, ap_instances, legacy_hal_, iface_util_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
}
}
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
return iface;
}
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> WifiChip::createApIfaceInternal() {
if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP)) {
return {std::shared_ptr<WifiApIface>(),
createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
std::string ifname = allocateApIfaceName();
ndk::ScopedAStatus status = createVirtualApInterface(ifname);
if (!status.isOk()) {
return {std::shared_ptr<WifiApIface>(), std::move(status)};
}
std::shared_ptr<WifiApIface> iface = newWifiApIface(ifname);
return {iface, ndk::ScopedAStatus::ok()};
}
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
WifiChip::createBridgedApIfaceInternal() {
if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
if (ap_instances.size() < 2) {
LOG(ERROR) << "Fail to allocate two instances";
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
for (int i = 0; i < 2; i++) {
ndk::ScopedAStatus status = createVirtualApInterface(ap_instances[i]);
if (!status.isOk()) {
if (i != 0) { // The failure happened when creating second virtual
// iface.
legacy_hal_.lock()->deleteVirtualInterface(
ap_instances.front()); // Remove the first virtual iface.
}
return {nullptr, std::move(status)};
}
}
br_ifaces_ap_instances_[br_ifname] = ap_instances;
if (!iface_util_->createBridge(br_ifname)) {
LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
deleteApIface(br_ifname);
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
for (auto const& instance : ap_instances) {
// Bind ap instance interface to AP bridge
if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
deleteApIface(br_ifname);
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
}
std::shared_ptr<WifiApIface> iface = newWifiApIface(br_ifname);
return {iface, ndk::ScopedAStatus::ok()};
}
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
WifiChip::createApOrBridgedApIfaceInternal(
IfaceConcurrencyType ifaceType, const std::vector<common::OuiKeyedData>& /* vendorData */) {
if (ifaceType == IfaceConcurrencyType::AP) {
return createApIfaceInternal();
} else if (ifaceType == IfaceConcurrencyType::AP_BRIDGED) {
return createBridgedApIfaceInternal();
} else {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
}
std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getApIfaceNamesInternal() {
if (ap_ifaces_.empty()) {
return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
}
return {getNames(ap_ifaces_), ndk::ScopedAStatus::ok()};
}
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> WifiChip::getApIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(ap_ifaces_, ifname);
if (!iface.get()) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
return {iface, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
const auto iface = findUsingName(ap_ifaces_, ifname);
if (!iface.get()) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
// Invalidate & remove any dependent objects first.
// Note: This is probably not required because we never create
// nan/rtt objects over AP iface. But, there is no harm to do it
// here and not make that assumption all over the place.
invalidateAndRemoveDependencies(ifname);
deleteApIface(ifname);
invalidateAndClear(ap_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
}
}
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal(
const std::string& ifname, const std::string& ifInstanceName) {
const auto iface = findUsingName(ap_ifaces_, ifname);
if (!iface.get() || ifInstanceName.empty()) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
// Requires to remove one of the instance in bridge mode
for (auto const& it : br_ifaces_ap_instances_) {
if (it.first == ifname) {
std::vector<std::string> ap_instances = it.second;
for (auto const& iface : ap_instances) {
if (iface == ifInstanceName) {
if (!iface_util_->removeIfaceFromBridge(it.first, iface)) {
LOG(ERROR) << "Failed to remove interface: " << ifInstanceName << " from "
<< ifname;
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->deleteVirtualInterface(iface);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to del interface: " << iface << " "
<< legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
ap_instances.erase(
std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName),
ap_instances.end());
br_ifaces_ap_instances_[ifname] = ap_instances;
break;
}
}
break;
}
}
iface->removeInstance(ifInstanceName);
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
return ndk::ScopedAStatus::ok();
}
std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> WifiChip::createNanIfaceInternal() {
if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::NAN_IFACE)) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
bool is_dedicated_iface = true;
std::string ifname = getPredefinedNanIfaceName();
if (ifname.empty() || !iface_util_->ifNameToIndex(ifname)) {
// Use the first shared STA iface (wlan0) if a dedicated aware iface is
// not defined.
ifname = getFirstActiveWlanIfaceName();
is_dedicated_iface = false;
}
std::shared_ptr<WifiNanIface> iface =
WifiNanIface::create(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
nan_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::NAN_IFACE, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
}
}
return {iface, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getNanIfaceNamesInternal() {
if (nan_ifaces_.empty()) {
return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
}
return {getNames(nan_ifaces_), ndk::ScopedAStatus::ok()};
}
std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> WifiChip::getNanIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(nan_ifaces_, ifname);
if (!iface.get()) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
return {iface, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
const auto iface = findUsingName(nan_ifaces_, ifname);
if (!iface.get()) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
invalidateAndClear(nan_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::NAN_IFACE, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
}
}
return ndk::ScopedAStatus::ok();
}
std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> WifiChip::createP2pIfaceInternal() {
if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::P2P)) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
std::string ifname = getPredefinedP2pIfaceName();
std::shared_ptr<WifiP2pIface> iface =
ndk::SharedRefBase::make<WifiP2pIface>(ifname, legacy_hal_);
p2p_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
}
}
return {iface, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getP2pIfaceNamesInternal() {
if (p2p_ifaces_.empty()) {
return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
}
return {getNames(p2p_ifaces_), ndk::ScopedAStatus::ok()};
}
std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> WifiChip::getP2pIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(p2p_ifaces_, ifname);
if (!iface.get()) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
return {iface, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
const auto iface = findUsingName(p2p_ifaces_, ifname);
if (!iface.get()) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
invalidateAndClear(p2p_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
}
}
return ndk::ScopedAStatus::ok();
}
std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> WifiChip::createStaIfaceInternal() {
if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
std::string ifname = allocateStaIfaceName();
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->createVirtualInterface(
ifname, aidl_struct_util::convertAidlIfaceTypeToLegacy(IfaceType::STA));
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to add interface: " << ifname << " "
<< legacyErrorToString(legacy_status);
return {nullptr, createWifiStatusFromLegacyError(legacy_status)};
}
std::shared_ptr<WifiStaIface> iface = WifiStaIface::create(ifname, legacy_hal_, iface_util_);
sta_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
}
}
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
return {iface, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getStaIfaceNamesInternal() {
if (sta_ifaces_.empty()) {
return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
}
return {getNames(sta_ifaces_), ndk::ScopedAStatus::ok()};
}
std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> WifiChip::getStaIfaceInternal(
const std::string& ifname) {
const auto iface = findUsingName(sta_ifaces_, ifname);
if (!iface.get()) {
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
return {iface, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
const auto iface = findUsingName(sta_ifaces_, ifname);
if (!iface.get()) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
// Invalidate & remove any dependent objects first.
invalidateAndRemoveDependencies(ifname);
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(ifname);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to remove interface: " << ifname << " "
<< legacyErrorToString(legacy_status);
}
invalidateAndClear(sta_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
}
}
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
return ndk::ScopedAStatus::ok();
}
std::pair<std::shared_ptr<IWifiRttController>, ndk::ScopedAStatus>
WifiChip::createRttControllerInternal(const std::shared_ptr<IWifiStaIface>& bound_iface) {
if (sta_ifaces_.size() == 0 &&
!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs "
"(and RTT by extension)";
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
}
std::shared_ptr<WifiRttController> rtt =
WifiRttController::create(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
rtt_controllers_.emplace_back(rtt);
return {rtt, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<WifiDebugRingBufferStatus>, ndk::ScopedAStatus>
WifiChip::getDebugRingBuffersStatusInternal() {
legacy_hal::wifi_error legacy_status;
std::vector<legacy_hal::wifi_ring_buffer_status> legacy_ring_buffer_status_vec;
std::tie(legacy_status, legacy_ring_buffer_status_vec) =
legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {std::vector<WifiDebugRingBufferStatus>(),
createWifiStatusFromLegacyError(legacy_status)};
}
std::vector<WifiDebugRingBufferStatus> aidl_ring_buffer_status_vec;
if (!aidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToAidl(
legacy_ring_buffer_status_vec, &aidl_ring_buffer_status_vec)) {
return {std::vector<WifiDebugRingBufferStatus>(),
createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_ring_buffer_status_vec, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::startLoggingToDebugRingBufferInternal(
const std::string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
ndk::ScopedAStatus status = registerDebugRingBufferCallback();
if (!status.isOk()) {
return status;
}
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRingBufferLogging(
getFirstActiveWlanIfaceName(), ring_name,
static_cast<std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(verbose_level),
max_interval_in_sec, min_data_size_in_bytes);
ringbuffer_map_.insert(
std::pair<std::string, Ringbuffer>(ring_name, Ringbuffer(kMaxBufferSizeBytes)));
// if verbose logging enabled, turn up HAL daemon logging as well.
if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) {
::android::base::SetMinimumLogSeverity(::android::base::DEBUG);
} else {
::android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
}
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::forceDumpToDebugRingBufferInternal(const std::string& ring_name) {
ndk::ScopedAStatus status = registerDebugRingBufferCallback();
if (!status.isOk()) {
return status;
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(), ring_name);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::flushRingBufferToFileInternal() {
if (!writeRingbufferFilesInternal()) {
LOG(ERROR) << "Error writing files to flash";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->deregisterRingBufferCallbackHandler(getFirstActiveWlanIfaceName());
if (legacy_status == legacy_hal::WIFI_SUCCESS) {
debug_ring_buffer_cb_registered_ = false;
}
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<WifiDebugHostWakeReasonStats, ndk::ScopedAStatus>
WifiChip::getDebugHostWakeReasonStatsInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::WakeReasonStats legacy_stats;
std::tie(legacy_status, legacy_stats) =
legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {WifiDebugHostWakeReasonStats{}, createWifiStatusFromLegacyError(legacy_status)};
}
WifiDebugHostWakeReasonStats aidl_stats;
if (!aidl_struct_util::convertLegacyWakeReasonStatsToAidl(legacy_stats, &aidl_stats)) {
return {WifiDebugHostWakeReasonStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_stats, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
legacy_hal::wifi_error legacy_status;
if (enable) {
std::weak_ptr<WifiChip> weak_ptr_this = weak_ptr_this_;
const auto& on_alert_callback = [weak_ptr_this](int32_t error_code,
std::vector<uint8_t> debug_data) {
const auto shared_ptr_this = weak_ptr_this.lock();
if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->onDebugErrorAlert(error_code, debug_data).isOk()) {
LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
}
}
};
legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
getFirstActiveWlanIfaceName(), on_alert_callback);
} else {
legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
getFirstActiveWlanIfaceName());
}
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::selectTxPowerScenarioInternal(IWifiChip::TxPowerScenario scenario) {
auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
getFirstActiveWlanIfaceName(),
aidl_struct_util::convertAidlTxPowerScenarioToLegacy(scenario));
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::resetTxPowerScenarioInternal() {
auto legacy_status = legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::setLatencyModeInternal(IWifiChip::LatencyMode mode) {
auto legacy_status = legacy_hal_.lock()->setLatencyMode(
getFirstActiveWlanIfaceName(), aidl_struct_util::convertAidlLatencyModeToLegacy(mode));
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::setMultiStaPrimaryConnectionInternal(const std::string& ifname) {
auto legacy_status = legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::setMultiStaUseCaseInternal(IWifiChip::MultiStaUseCase use_case) {
auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase(
aidl_struct_util::convertAidlMultiStaUseCaseToLegacy(use_case));
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::setCoexUnsafeChannelsInternal(
std::vector<IWifiChip::CoexUnsafeChannel> unsafe_channels, int32_t aidl_restrictions) {
std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
if (!aidl_struct_util::convertAidlVectorOfCoexUnsafeChannelToLegacy(unsafe_channels,
&legacy_unsafe_channels)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
uint32_t legacy_restrictions = 0;
if (aidl_restrictions & static_cast<uint32_t>(CoexRestriction::WIFI_DIRECT)) {
legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_DIRECT;
}
if (aidl_restrictions & static_cast<uint32_t>(CoexRestriction::SOFTAP)) {
legacy_restrictions |= legacy_hal::wifi_coex_restriction::SOFTAP;
}
if (aidl_restrictions & static_cast<uint32_t>(CoexRestriction::WIFI_AWARE)) {
legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_AWARE;
}
auto legacy_status =
legacy_hal_.lock()->setCoexUnsafeChannels(legacy_unsafe_channels, legacy_restrictions);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::setCountryCodeInternal(const std::array<uint8_t, 2>& code) {
auto legacy_status = legacy_hal_.lock()->setCountryCode(getFirstActiveWlanIfaceName(), code);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<std::vector<WifiUsableChannel>, ndk::ScopedAStatus> WifiChip::getUsableChannelsInternal(
WifiBand band, int32_t ifaceModeMask, int32_t filterMask) {
legacy_hal::wifi_error legacy_status;
std::vector<legacy_hal::wifi_usable_channel> legacy_usable_channels;
std::tie(legacy_status, legacy_usable_channels) = legacy_hal_.lock()->getUsableChannels(
aidl_struct_util::convertAidlWifiBandToLegacyMacBand(band),
aidl_struct_util::convertAidlWifiIfaceModeToLegacy(ifaceModeMask),
aidl_struct_util::convertAidlUsableChannelFilterToLegacy(filterMask));
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {std::vector<WifiUsableChannel>(), createWifiStatusFromLegacyError(legacy_status)};
}
std::vector<WifiUsableChannel> aidl_usable_channels;
if (!aidl_struct_util::convertLegacyWifiUsableChannelsToAidl(legacy_usable_channels,
&aidl_usable_channels)) {
return {std::vector<WifiUsableChannel>(), createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_usable_channels, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::setAfcChannelAllowanceInternal(
const AfcChannelAllowance& afcChannelAllowance) {
LOG(INFO) << "setAfcChannelAllowance is not yet supported. availableAfcFrequencyInfos size="
<< afcChannelAllowance.availableAfcFrequencyInfos.size()
<< " availableAfcChannelInfos size="
<< afcChannelAllowance.availableAfcChannelInfos.size()
<< " availabilityExpireTimeMs=" << afcChannelAllowance.availabilityExpireTimeMs;
return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
std::pair<std::vector<WifiRadioCombination>, ndk::ScopedAStatus>
WifiChip::getSupportedRadioCombinationsInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_radio_combination_matrix* legacy_matrix;
std::vector<WifiRadioCombination> aidl_combinations;
std::tie(legacy_status, legacy_matrix) =
legacy_hal_.lock()->getSupportedRadioCombinationsMatrix();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to get SupportedRadioCombinations matrix from legacy HAL: "
<< legacyErrorToString(legacy_status);
if (legacy_matrix != nullptr) {
free(legacy_matrix);
}
return {aidl_combinations, createWifiStatusFromLegacyError(legacy_status)};
}
if (!aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix,
&aidl_combinations)) {
LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToAidl() ";
if (legacy_matrix != nullptr) {
free(legacy_matrix);
}
return {aidl_combinations, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
if (legacy_matrix != nullptr) {
free(legacy_matrix);
}
return {aidl_combinations, ndk::ScopedAStatus::ok()};
}
std::pair<WifiChipCapabilities, ndk::ScopedAStatus> WifiChip::getWifiChipCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_chip_capabilities legacy_chip_capabilities;
std::tie(legacy_status, legacy_chip_capabilities) =
legacy_hal_.lock()->getWifiChipCapabilities();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to get chip capabilities from legacy HAL: "
<< legacyErrorToString(legacy_status);
return {WifiChipCapabilities(), createWifiStatusFromLegacyError(legacy_status)};
}
WifiChipCapabilities aidl_chip_capabilities;
if (!aidl_struct_util::convertLegacyWifiChipCapabilitiesToAidl(legacy_chip_capabilities,
aidl_chip_capabilities)) {
LOG(ERROR) << "Failed convertLegacyWifiChipCapabilitiesToAidl() ";
return {WifiChipCapabilities(), createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetworkInternal(
int32_t channelCategoryEnableFlag) {
auto legacy_status = legacy_hal_.lock()->enableStaChannelForPeerNetwork(
aidl_struct_util::convertAidlChannelCategoryToLegacy(channelCategoryEnableFlag));
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::triggerSubsystemRestartInternal() {
auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::handleChipConfiguration(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, int32_t 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 (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 == feature_flags::chip_mode_ids::kV1Sta) {
success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
} else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
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.
ndk::ScopedAStatus status = registerRadioModeChangeCallback();
if (!status.isOk()) {
// This is probably not a critical failure?
LOG(ERROR) << "Failed to register radio mode change callback";
}
// Extract and save the version information into property.
std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> version_info;
version_info = WifiChip::requestChipDebugInfoInternal();
if (version_info.second.isOk()) {
property_set("vendor.wlan.firmware.version",
version_info.first.firmwareDescription.c_str());
property_set("vendor.wlan.driver.version", version_info.first.driverDescription.c_str());
}
// Get the driver supported interface combination.
retrieveDynamicIfaceCombination();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus WifiChip::registerDebugRingBufferCallback() {
if (debug_ring_buffer_cb_registered_) {
return ndk::ScopedAStatus::ok();
}
std::weak_ptr<WifiChip> weak_ptr_this = weak_ptr_this_;
const auto& on_ring_buffer_data_callback =
[weak_ptr_this](const std::string& name, const std::vector<uint8_t>& data,
const legacy_hal::wifi_ring_buffer_status& status) {
const auto shared_ptr_this = weak_ptr_this.lock();
if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
WifiDebugRingBufferStatus aidl_status;
Ringbuffer::AppendStatus appendstatus;
if (!aidl_struct_util::convertLegacyDebugRingBufferStatusToAidl(status,
&aidl_status)) {
LOG(ERROR) << "Error converting ring buffer status";
return;
}
{
std::unique_lock<std::mutex> lk(shared_ptr_this->lock_t);
const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
if (target != shared_ptr_this->ringbuffer_map_.end()) {
Ringbuffer& cur_buffer = target->second;
appendstatus = cur_buffer.append(data);
} else {
LOG(ERROR) << "Ringname " << name << " not found";
return;
}
// unique_lock unlocked here
}
if (appendstatus == Ringbuffer::AppendStatus::FAIL_RING_BUFFER_CORRUPTED) {
LOG(ERROR) << "Ringname " << name << " is corrupted. Clear the ring buffer";
shared_ptr_this->writeRingbufferFilesInternal();
return;
}
};
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler(
getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
if (legacy_status == legacy_hal::WIFI_SUCCESS) {
debug_ring_buffer_cb_registered_ = true;
}
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiChip::registerRadioModeChangeCallback() {
std::weak_ptr<WifiChip> weak_ptr_this = weak_ptr_this_;
const auto& on_radio_mode_change_callback =
[weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
const auto shared_ptr_this = weak_ptr_this.lock();
if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
LOG(ERROR) << "Callback invoked on an invalid object";
return;
}
std::vector<IWifiChipEventCallback::RadioModeInfo> aidl_radio_mode_infos;
if (!aidl_struct_util::convertLegacyWifiMacInfosToAidl(mac_infos,
&aidl_radio_mode_infos)) {
LOG(ERROR) << "Error converting wifi mac info";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->onRadioModeChange(aidl_radio_mode_infos).isOk()) {
LOG(ERROR) << "Failed to invoke onRadioModeChange callback";
}
}
};
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
return createWifiStatusFromLegacyError(legacy_status);
}
std::vector<IWifiChip::ChipConcurrencyCombination>
WifiChip::getCurrentModeConcurrencyCombinations() {
if (!isValidModeId(current_mode_id_)) {
LOG(ERROR) << "Chip not configured in a mode yet";
return std::vector<IWifiChip::ChipConcurrencyCombination>();
}
for (const auto& mode : modes_) {
if (mode.id == current_mode_id_) {
return mode.availableCombinations;
}
}
CHECK(0) << "Expected to find concurrency combinations for current mode!";
return std::vector<IWifiChip::ChipConcurrencyCombination>();
}
// Returns a map indexed by IfaceConcurrencyType with the number of ifaces currently
// created of the corresponding concurrency type.
std::map<IfaceConcurrencyType, size_t> WifiChip::getCurrentConcurrencyCombination() {
std::map<IfaceConcurrencyType, size_t> iface_counts;
uint32_t num_ap = 0;
uint32_t num_ap_bridged = 0;
for (const auto& ap_iface : ap_ifaces_) {
std::string ap_iface_name = ap_iface->getName();
if (br_ifaces_ap_instances_.count(ap_iface_name) > 0 &&
br_ifaces_ap_instances_[ap_iface_name].size() > 1) {
num_ap_bridged++;
} else {
num_ap++;
}
}
iface_counts[IfaceConcurrencyType::AP] = num_ap;
iface_counts[IfaceConcurrencyType::AP_BRIDGED] = num_ap_bridged;
iface_counts[IfaceConcurrencyType::NAN_IFACE] = nan_ifaces_.size();
iface_counts[IfaceConcurrencyType::P2P] = p2p_ifaces_.size();
iface_counts[IfaceConcurrencyType::STA] = sta_ifaces_.size();
return iface_counts;
}
// This expands the provided concurrency combinations to a more parseable
// form. Returns a vector of available combinations possible with the number
// of each concurrency type in the combination.
// This method is a port of HalDeviceManager.expandConcurrencyCombos() from framework.
std::vector<std::map<IfaceConcurrencyType, size_t>> WifiChip::expandConcurrencyCombinations(
const IWifiChip::ChipConcurrencyCombination& combination) {
int32_t num_expanded_combos = 1;
for (const auto& limit : combination.limits) {
for (int32_t i = 0; i < limit.maxIfaces; i++) {
num_expanded_combos *= limit.types.size();
}
}
// Allocate the vector of expanded combos and reset all concurrency type counts to 0
// in each combo.
std::vector<std::map<IfaceConcurrencyType, size_t>> expanded_combos;
expanded_combos.resize(num_expanded_combos);
for (auto& expanded_combo : expanded_combos) {
for (const auto type : {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED,
IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P,
IfaceConcurrencyType::STA}) {
expanded_combo[type] = 0;
}
}
int32_t span = num_expanded_combos;
for (const auto& limit : combination.limits) {
for (int32_t i = 0; i < limit.maxIfaces; i++) {
span /= limit.types.size();
for (int32_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::canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(
const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
IfaceConcurrencyType requested_type) {
const auto current_combo = getCurrentConcurrencyCombination();
// Check if we have space for 1 more iface of |type| in this combo
for (const auto type :
{IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED,
IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
size_t num_ifaces_needed = current_combo.at(type);
if (type == requested_type) {
num_ifaces_needed++;
}
size_t num_ifaces_allowed = expanded_combo.at(type);
if (num_ifaces_needed > num_ifaces_allowed) {
return false;
}
}
return true;
}
// This method does the following:
// a) Enumerate all possible concurrency combos by expanding the current
// ChipConcurrencyCombination.
// b) Check if the requested concurrency type can be added to the current mode
// with the concurrency combination that is already active.
bool WifiChip::canCurrentModeSupportConcurrencyTypeWithCurrentTypes(
IfaceConcurrencyType requested_type) {
if (!isValidModeId(current_mode_id_)) {
LOG(ERROR) << "Chip not configured in a mode yet";
return false;
}
const auto combinations = getCurrentModeConcurrencyCombinations();
for (const auto& combination : combinations) {
const auto expanded_combos = expandConcurrencyCombinations(combination);
for (const auto& expanded_combo : expanded_combos) {
if (canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(expanded_combo,
requested_type)) {
return true;
}
}
}
return false;
}
// Note: This does not consider concurrency types already active. It only checks if the
// provided expanded concurrency combination can support the requested combo.
bool WifiChip::canExpandedConcurrencyComboSupportConcurrencyCombo(
const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
const std::map<IfaceConcurrencyType, size_t>& req_combo) {
// Check if we have space for 1 more |type| in this combo
for (const auto type :
{IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED,
IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
if (req_combo.count(type) == 0) {
// Concurrency type not in the req_combo.
continue;
}
size_t num_ifaces_needed = req_combo.at(type);
size_t num_ifaces_allowed = expanded_combo.at(type);
if (num_ifaces_needed > num_ifaces_allowed) {
return false;
}
}
return true;
}
// This method does the following:
// a) Enumerate all possible concurrency combos by expanding the current
// ChipConcurrencyCombination.
// b) Check if the requested concurrency combo can be added to the current mode.
// Note: This does not consider concurrency types already active. It only checks if the
// current mode can support the requested combo.
bool WifiChip::canCurrentModeSupportConcurrencyCombo(
const std::map<IfaceConcurrencyType, size_t>& req_combo) {
if (!isValidModeId(current_mode_id_)) {
LOG(ERROR) << "Chip not configured in a mode yet";
return false;
}
const auto combinations = getCurrentModeConcurrencyCombinations();
for (const auto& combination : combinations) {
const auto expanded_combos = expandConcurrencyCombinations(combination);
for (const auto& expanded_combo : expanded_combos) {
if (canExpandedConcurrencyComboSupportConcurrencyCombo(expanded_combo, req_combo)) {
return true;
}
}
}
return false;
}
// This method does the following:
// a) Enumerate all possible concurrency combos by expanding the current
// ChipConcurrencyCombination.
// b) Check if the requested concurrency type can be added to the current mode.
bool WifiChip::canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type) {
// Check if we can support at least 1 of the requested concurrency type.
std::map<IfaceConcurrencyType, size_t> req_iface_combo;
req_iface_combo[requested_type] = 1;
return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
}
bool WifiChip::isValidModeId(int32_t mode_id) {
for (const auto& mode : modes_) {
if (mode.id == mode_id) {
return true;
}
}
return false;
}
bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
// Check if we can support at least 1 STA & 1 AP concurrently.
std::map<IfaceConcurrencyType, size_t> req_iface_combo;
req_iface_combo[IfaceConcurrencyType::STA] = 1;
req_iface_combo[IfaceConcurrencyType::AP] = 1;
return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
}
bool WifiChip::isDualStaConcurrencyAllowedInCurrentMode() {
// Check if we can support at least 2 STA concurrently.
std::map<IfaceConcurrencyType, size_t> req_iface_combo;
req_iface_combo[IfaceConcurrencyType::STA] = 2;
return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
}
std::string WifiChip::getFirstActiveWlanIfaceName() {
if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
if (ap_ifaces_.size() > 0) {
// If the first active wlan iface is bridged iface.
// Return first instance name.
for (auto const& it : br_ifaces_ap_instances_) {
if (it.first == ap_ifaces_[0]->getName()) {
return it.second[0];
}
}
return ap_ifaces_[0]->getName();
}
// This could happen if the chip call is made before any STA/AP
// iface is created. Default to wlan0 for such cases.
LOG(WARNING) << "No active wlan interfaces in use! Using default";
return getWlanIfaceNameWithType(IfaceType::STA, 0);
}
// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
// not already in use.
// Note: This doesn't check the actual presence of these interfaces.
std::string WifiChip::allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx) {
for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
const auto ifname = getWlanIfaceNameWithType(type, idx);
if (findUsingNameFromBridgedApInstances(ifname)) continue;
if (findUsingName(ap_ifaces_, ifname)) continue;
if (findUsingName(sta_ifaces_, ifname)) continue;
return ifname;
}
// This should never happen. We screwed up somewhere if it did.
CHECK(false) << "All wlan interfaces in use already!";
return {};
}
uint32_t WifiChip::startIdxOfApIface() {
if (isDualStaConcurrencyAllowedInCurrentMode()) {
// When the HAL support dual STAs, AP should start with idx 2.
return 2;
} else if (isStaApConcurrencyAllowedInCurrentMode()) {
// When the HAL support STA + AP but it doesn't support dual STAs.
// AP should start with idx 1.
return 1;
}
// No concurrency support.
return 0;
}
// AP iface names start with idx 1 for modes supporting
// concurrent STA and not dual AP, else start with idx 0.
std::string WifiChip::allocateApIfaceName() {
// Check if we have a dedicated iface for AP.
std::vector<std::string> ifnames = getPredefinedApIfaceNames(true);
for (auto const& ifname : ifnames) {
if (findUsingName(ap_ifaces_, ifname)) continue;
return ifname;
}
return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
}
std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
// Check if we have a dedicated iface for AP.
std::vector<std::string> instances = getPredefinedApIfaceNames(true);
if (instances.size() == 2) {
return instances;
} else {
int num_ifaces_need_to_allocate = 2 - instances.size();
for (int i = 0; i < num_ifaces_need_to_allocate; i++) {
std::string instance_name =
allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface() + i);
if (!instance_name.empty()) {
instances.push_back(instance_name);
}
}
}
return instances;
}
// STA iface names start with idx 0.
// Primary STA iface will always be 0.
std::string WifiChip::allocateStaIfaceName() {
return allocateApOrStaIfaceName(IfaceType::STA, 0);
}
bool WifiChip::writeRingbufferFilesInternal() {
if (!removeOldFilesInternal()) {
LOG(ERROR) << "Error occurred while deleting old tombstone files";
return false;
}
// write ringbuffers to file
{
std::unique_lock<std::mutex> lk(lock_t);
for (auto& item : ringbuffer_map_) {
Ringbuffer& cur_buffer = item.second;
if (cur_buffer.getData().empty()) {
continue;
}
const std::string file_path_raw = kTombstoneFolderPath + item.first + "XXXXXXXXXX";
const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
if (dump_fd == -1) {
PLOG(ERROR) << "create file failed";
return false;
}
unique_fd file_auto_closer(dump_fd);
for (const auto& cur_block : cur_buffer.getData()) {
if (cur_block.size() <= 0 || cur_block.size() > kMaxBufferSizeBytes) {
PLOG(ERROR) << "Ring buffer: " << item.first
<< " is corrupted. Invalid block size: " << cur_block.size();
break;
}
if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) ==
-1) {
PLOG(ERROR) << "Error writing to file";
}
}
cur_buffer.clear();
}
// unique_lock unlocked here
}
return true;
}
std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
std::string ifname;
// let the legacy hal override the interface name
legacy_hal::wifi_error err = legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
if (err == legacy_hal::WIFI_SUCCESS) return ifname;
return getWlanIfaceName(idx);
}
void WifiChip::invalidateAndClearBridgedApAll() {
for (auto const& it : br_ifaces_ap_instances_) {
for (auto const& iface : it.second) {
iface_util_->removeIfaceFromBridge(it.first, iface);
legacy_hal_.lock()->deleteVirtualInterface(iface);
}
iface_util_->deleteBridge(it.first);
}
br_ifaces_ap_instances_.clear();
}
void WifiChip::deleteApIface(const std::string& if_name) {
if (if_name.empty()) return;
// delete bridged interfaces if any
for (auto const& it : br_ifaces_ap_instances_) {
if (it.first == if_name) {
for (auto const& iface : it.second) {
iface_util_->removeIfaceFromBridge(if_name, iface);
legacy_hal_.lock()->deleteVirtualInterface(iface);
}
iface_util_->deleteBridge(if_name);
br_ifaces_ap_instances_.erase(if_name);
// ifname is bridged AP, return here.
return;
}
}
// No bridged AP case, delete AP iface
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(if_name);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to remove interface: " << if_name << " "
<< legacyErrorToString(legacy_status);
}
}
bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
for (auto const& it : br_ifaces_ap_instances_) {
if (it.first == name) {
return true;
}
for (auto const& iface : it.second) {
if (iface == name) {
return true;
}
}
}
return false;
}
ndk::ScopedAStatus WifiChip::setMloModeInternal(const WifiChip::ChipMloMode in_mode) {
legacy_hal::wifi_mlo_mode mode;
switch (in_mode) {
case WifiChip::ChipMloMode::DEFAULT:
mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_DEFAULT;
break;
case WifiChip::ChipMloMode::LOW_LATENCY:
mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_LOW_LATENCY;
break;
case WifiChip::ChipMloMode::HIGH_THROUGHPUT:
mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_HIGH_THROUGHPUT;
break;
case WifiChip::ChipMloMode::LOW_POWER:
mode = legacy_hal::wifi_mlo_mode::WIFI_MLO_MODE_LOW_POWER;
break;
default:
PLOG(ERROR) << "Error: invalid mode: " << toString(in_mode);
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
return createWifiStatusFromLegacyError(legacy_hal_.lock()->setMloMode(mode));
}
ndk::ScopedAStatus WifiChip::setVoipModeInternal(const WifiChip::VoipMode in_mode) {
const auto ifname = getFirstActiveWlanIfaceName();
wifi_voip_mode mode;
switch (in_mode) {
case WifiChip::VoipMode::VOICE:
mode = wifi_voip_mode::WIFI_VOIP_MODE_VOICE;
break;
case WifiChip::VoipMode::OFF:
mode = wifi_voip_mode::WIFI_VOIP_MODE_OFF;
break;
default:
PLOG(ERROR) << "Error: invalid mode: " << toString(in_mode);
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
return createWifiStatusFromLegacyError(legacy_hal_.lock()->setVoipMode(ifname, mode));
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl