Add AIDL implementation for the vendor HAL service.

Bug: 205044134
Test: Pass AIDL VTS tests and regression tests.
Change-Id: Iad04ce01f71fc220443e05a4be05d7d5545227e8
This commit is contained in:
Gabriel Biren
2022-07-15 23:25:39 +00:00
committed by Mahesh KKV
parent da9b3895d2
commit f3262f970d
67 changed files with 17187 additions and 0 deletions

View File

@@ -0,0 +1,214 @@
// 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.
package {
default_applicable_licenses: ["hardware_interfaces_license"],
}
soong_config_module_type {
name: "wifi_hal_cc_defaults",
module_type: "cc_defaults",
config_namespace: "wifi",
bool_variables: [
"hidl_feature_aware", // WIFI_HIDL_FEATURE_AWARE
"hidl_feature_dual_interface", // WIFI_HIDL_FEATURE_DUAL_INTERFACE
"hidl_feature_disable_ap", // WIFI_HIDL_FEATURE_DISABLE_AP
"hidl_feature_disable_ap_mac_randomization", // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
"avoid_iface_reset_mac_change", // WIFI_AVOID_IFACE_RESET_MAC_CHANGE
],
value_variables: [
"hal_interface_combinations", // WIFI_HAL_INTERFACE_COMBINATIONS
],
properties: [
"cppflags",
],
}
wifi_hal_cc_defaults {
name: "android.hardware.wifi-service-cppflags-defaults",
soong_config_variables: {
hidl_feature_aware: {
cppflags: ["-DWIFI_HIDL_FEATURE_AWARE"],
},
hidl_feature_dual_interface: {
cppflags: ["-DWIFI_HIDL_FEATURE_DUAL_INTERFACE"],
},
hidl_feature_disable_ap: {
cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP"],
},
hidl_feature_disable_ap_mac_randomization: {
cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION"],
},
avoid_iface_reset_mac_change: {
cppflags: ["-DWIFI_AVOID_IFACE_RESET_MAC_CHANGE"],
},
hal_interface_combinations: {
cppflags: ["-DWIFI_HAL_INTERFACE_COMBINATIONS=%s"],
},
},
}
cc_library_static {
name: "android.hardware.wifi-service-lib",
defaults: ["android.hardware.wifi-service-cppflags-defaults"],
proprietary: true,
compile_multilib: "first",
cppflags: [
"-Wall",
"-Werror",
"-Wextra",
],
// Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
cflags: ["-Wno-error=implicit-fallthrough"],
srcs: [
"aidl_struct_util.cpp",
"aidl_sync_util.cpp",
"ringbuffer.cpp",
"wifi.cpp",
"wifi_ap_iface.cpp",
"wifi_chip.cpp",
"wifi_feature_flags.cpp",
"wifi_iface_util.cpp",
"wifi_legacy_hal.cpp",
"wifi_legacy_hal_factory.cpp",
"wifi_legacy_hal_stubs.cpp",
"wifi_mode_controller.cpp",
"wifi_nan_iface.cpp",
"wifi_p2p_iface.cpp",
"wifi_rtt_controller.cpp",
"wifi_sta_iface.cpp",
"wifi_status_util.cpp",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
"libnl",
"libutils",
"libwifi-hal",
"libwifi-system-iface",
"libxml2",
"android.hardware.wifi-V1-ndk",
],
export_include_dirs: ["."],
}
cc_binary {
name: "android.hardware.wifi-service",
vintf_fragments: ["android.hardware.wifi-service.xml"],
relative_install_path: "hw",
proprietary: true,
cppflags: [
"-Wall",
"-Werror",
"-Wextra",
],
srcs: ["service.cpp"],
shared_libs: [
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
"libnl",
"libutils",
"libwifi-hal",
"libwifi-system-iface",
"libxml2",
"android.hardware.wifi-V1-ndk",
],
static_libs: ["android.hardware.wifi-service-lib"],
init_rc: ["android.hardware.wifi-service.rc"],
}
cc_binary {
name: "android.hardware.wifi-service-lazy",
vintf_fragments: ["android.hardware.wifi-service.xml"],
overrides: ["android.hardware.wifi-service"],
cflags: ["-DLAZY_SERVICE"],
relative_install_path: "hw",
proprietary: true,
cppflags: [
"-Wall",
"-Werror",
"-Wextra",
],
srcs: ["service.cpp"],
shared_libs: [
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
"libnl",
"libutils",
"libwifi-hal",
"libwifi-system-iface",
"libxml2",
"android.hardware.wifi-V1-ndk",
],
static_libs: ["android.hardware.wifi-service-lib"],
init_rc: ["android.hardware.wifi-service-lazy.rc"],
}
cc_test {
name: "android.hardware.wifi-service-tests",
proprietary: true,
compile_multilib: "first",
cppflags: [
"-Wall",
"-Werror",
"-Wextra",
],
srcs: [
"tests/aidl_struct_util_unit_tests.cpp",
"tests/main.cpp",
"tests/mock_interface_tool.cpp",
"tests/mock_wifi_feature_flags.cpp",
"tests/mock_wifi_iface_util.cpp",
"tests/mock_wifi_legacy_hal.cpp",
"tests/mock_wifi_mode_controller.cpp",
"tests/ringbuffer_unit_tests.cpp",
"tests/wifi_nan_iface_unit_tests.cpp",
"tests/wifi_chip_unit_tests.cpp",
"tests/wifi_iface_util_unit_tests.cpp",
],
static_libs: [
"libgmock",
"libgtest",
"android.hardware.wifi-V1-ndk",
"android.hardware.wifi-service-lib",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
"libnl",
"libutils",
"libwifi-hal",
"libwifi-system-iface",
],
}
filegroup {
name: "default-android.hardware.wifi-service.rc",
srcs: ["android.hardware.wifi-service.rc"],
}
filegroup {
name: "default-android.hardware.wifi-service.xml",
srcs: ["android.hardware.wifi-service.xml"],
}

View File

@@ -0,0 +1,35 @@
Vendor HAL Threading Model
==========================
The vendor HAL service has two threads:
1. AIDL thread: This is the main thread which processes all the incoming AIDL
RPC's.
2. Legacy HAL event loop thread: This is the thread forked off for processing
the legacy HAL event loop (wifi_event_loop()). This thread is used to process
any asynchronous netlink events posted by the driver. Any asynchronous
callbacks passed to the legacy HAL API's are invoked on this thread.
Synchronization Concerns
========================
wifi_legacy_hal.cpp has a bunch of global "C" style functions to handle the
legacy callbacks. Each of these "C" style functions invokes a corresponding
"std::function" version of the callback which does the actual processing.
The variables holding these "std::function" callbacks are reset from the AIDL
thread when they are no longer used. For example: stopGscan() will reset the
corresponding "on_gscan_*" callback variables which were set when startGscan()
was invoked. This is not thread safe since these callback variables are
accesed from the legacy hal event loop thread as well.
Synchronization Solution
========================
Adding a global lock seems to be the most trivial solution to the problem.
a) All of the asynchronous "C" style callbacks will acquire the global lock
before invoking the corresponding "std::function" callback variables.
b) All of the AIDL methods will also acquire the global lock before processing
(in aidl_return_util::validateAndCall()).
Note: It's important that we only acquire the global lock for asynchronous
callbacks, because there is no guarantee (or documentation to clarify) that the
synchronous callbacks are invoked on the same invocation thread. If that is not
the case in some implementation, we will end up deadlocking the system since the
AIDL thread would have acquired the global lock which is needed by the
synchronous callback executed on the legacy hal event loop thread.

View File

@@ -0,0 +1,140 @@
/*
* 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.
*/
#ifndef AIDL_CALLBACK_UTIL_H_
#define AIDL_CALLBACK_UTIL_H_
#include <android-base/logging.h>
#include <set>
#include <unordered_map>
namespace {
std::unordered_map<void* /* callback */, void* /* handler */> callback_handler_map_;
}
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace aidl_callback_util {
// Provides a class to manage callbacks for the various AIDL interfaces and
// handle the death of the process hosting each callback.
template <typename CallbackType>
class AidlCallbackHandler {
public:
AidlCallbackHandler() {
death_handler_ = AIBinder_DeathRecipient_new(AidlCallbackHandler::onCallbackDeath);
}
~AidlCallbackHandler() { invalidate(); }
bool addCallback(const std::shared_ptr<CallbackType>& cb) {
void* cbPtr = reinterpret_cast<void*>(cb->asBinder().get());
const auto& cbPosition = findCbInSet(cbPtr);
if (cbPosition != cb_set_.end()) {
LOG(WARNING) << "Duplicate death notification registration";
return true;
}
if (AIBinder_linkToDeath(cb->asBinder().get(), death_handler_, cbPtr /* cookie */) !=
STATUS_OK) {
LOG(ERROR) << "Failed to register death notification";
return false;
}
callback_handler_map_[cbPtr] = reinterpret_cast<void*>(this);
cb_set_.insert(cb);
return true;
}
const std::set<std::shared_ptr<CallbackType>>& getCallbacks() { return cb_set_; }
void invalidate() {
for (auto cb : cb_set_) {
void* cookie = reinterpret_cast<void*>(cb->asBinder().get());
if (AIBinder_unlinkToDeath(cb->asBinder().get(), death_handler_, cookie) != STATUS_OK) {
LOG(ERROR) << "Failed to deregister death notification";
}
if (!removeCbFromHandlerMap(cookie)) {
LOG(ERROR) << "Failed to remove callback from handler map";
}
}
cb_set_.clear();
}
// Entry point for the death handling logic. AIBinder_DeathRecipient
// can only call a static function, so use the cookie to find the
// proper handler and route the request there.
static void onCallbackDeath(void* cookie) {
auto cbQuery = callback_handler_map_.find(cookie);
if (cbQuery == callback_handler_map_.end()) {
LOG(ERROR) << "Invalid death cookie received";
return;
}
AidlCallbackHandler* cbHandler = reinterpret_cast<AidlCallbackHandler*>(cbQuery->second);
if (cbHandler == nullptr) {
LOG(ERROR) << "Handler mapping contained an invalid handler";
return;
}
cbHandler->handleCallbackDeath(cbQuery->first);
}
private:
std::set<std::shared_ptr<CallbackType>> cb_set_;
AIBinder_DeathRecipient* death_handler_;
typename std::set<std::shared_ptr<CallbackType>>::iterator findCbInSet(void* cbPtr) {
const auto& cbPosition = std::find_if(
cb_set_.begin(), cb_set_.end(), [cbPtr](const std::shared_ptr<CallbackType>& p) {
return cbPtr == reinterpret_cast<void*>(p->asBinder().get());
});
return cbPosition;
}
bool removeCbFromHandlerMap(void* cbPtr) {
auto cbQuery = callback_handler_map_.find(cbPtr);
if (cbQuery != callback_handler_map_.end()) {
callback_handler_map_.erase(cbQuery);
return true;
}
return false;
}
void handleCallbackDeath(void* cbPtr) {
const auto& cbPosition = findCbInSet(cbPtr);
if (cbPosition == cb_set_.end()) {
LOG(ERROR) << "Unknown callback death notification received";
return;
}
cb_set_.erase(cbPosition);
if (!removeCbFromHandlerMap(cbPtr)) {
LOG(ERROR) << "Callback was not in callback handler map";
}
}
DISALLOW_COPY_AND_ASSIGN(AidlCallbackHandler);
};
} // namespace aidl_callback_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // AIDL_CALLBACK_UTIL_H_

View File

@@ -0,0 +1,85 @@
/*
* 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.
*/
#ifndef AIDL_RETURN_UTIL_H_
#define AIDL_RETURN_UTIL_H_
#include "aidl_sync_util.h"
#include "wifi_status_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace aidl_return_util {
using aidl::android::hardware::wifi::WifiStatusCode;
using aidl::android::hardware::wifi::aidl_sync_util::acquireGlobalLock;
/**
* These utility functions are used to invoke a method on the provided
* AIDL interface object.
* These functions checks if the provided AIDL interface object is valid.
* a) If valid, Invokes the corresponding internal implementation function of
* the AIDL method.
* b) If invalid, return without calling the internal implementation function.
*/
// Use for AIDL methods which return only an AIDL status.
template <typename ObjT, typename WorkFuncT, typename... Args>
::ndk::ScopedAStatus validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid,
WorkFuncT&& work, Args&&... args) {
const auto lock = acquireGlobalLock();
if (obj->isValid()) {
return (obj->*work)(std::forward<Args>(args)...);
} else {
return createWifiStatus(status_code_if_invalid);
}
}
// Use for AIDL methods which return only an AIDL status.
// This version passes the global lock acquired to the body of the method.
template <typename ObjT, typename WorkFuncT, typename... Args>
::ndk::ScopedAStatus validateAndCallWithLock(ObjT* obj, WifiStatusCode status_code_if_invalid,
WorkFuncT&& work, Args&&... args) {
auto lock = acquireGlobalLock();
if (obj->isValid()) {
return (obj->*work)(&lock, std::forward<Args>(args)...);
} else {
return createWifiStatus(status_code_if_invalid);
}
}
// Use for AIDL methods which have a return value along with the AIDL status
template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
::ndk::ScopedAStatus validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid,
WorkFuncT&& work, ReturnT* ret_val, Args&&... args) {
const auto lock = acquireGlobalLock();
if (obj->isValid()) {
auto call_pair = (obj->*work)(std::forward<Args>(args)...);
*ret_val = call_pair.first;
return std::forward<::ndk::ScopedAStatus>(call_pair.second);
} else {
return ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(status_code_if_invalid));
}
}
} // namespace aidl_return_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // AIDL_RETURN_UTIL_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
/*
* 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.
*/
#ifndef AIDL_STRUCT_UTIL_H_
#define AIDL_STRUCT_UTIL_H_
#include <aidl/android/hardware/wifi/IWifiChip.h>
#include <aidl/android/hardware/wifi/IWifiChipEventCallback.h>
#include <aidl/android/hardware/wifi/NanBandIndex.h>
#include <aidl/android/hardware/wifi/WifiDebugRingBufferFlags.h>
#include <vector>
#include "wifi_legacy_hal.h"
/**
* This file contains a bunch of functions to convert structs from the legacy
* HAL to AIDL and vice versa.
*/
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace aidl_struct_util {
// Chip conversion methods.
bool convertLegacyFeaturesToAidlChipCapabilities(uint64_t legacy_feature_set,
uint32_t legacy_logger_feature_set,
uint32_t* aidl_caps);
bool convertLegacyDebugRingBufferStatusToAidl(
const legacy_hal::wifi_ring_buffer_status& legacy_status,
WifiDebugRingBufferStatus* aidl_status);
bool convertLegacyVectorOfDebugRingBufferStatusToAidl(
const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
std::vector<WifiDebugRingBufferStatus>* aidl_status_vec);
bool convertLegacyWakeReasonStatsToAidl(const legacy_hal::WakeReasonStats& legacy_stats,
WifiDebugHostWakeReasonStats* aidl_stats);
legacy_hal::wifi_power_scenario convertAidlTxPowerScenarioToLegacy(
IWifiChip::TxPowerScenario aidl_scenario);
legacy_hal::wifi_latency_mode convertAidlLatencyModeToLegacy(
IWifiChip::LatencyMode aidl_latency_mode);
bool convertLegacyWifiMacInfosToAidl(
const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
std::vector<IWifiChipEventCallback::RadioModeInfo>* aidl_radio_mode_infos);
legacy_hal::wifi_interface_type convertAidlIfaceTypeToLegacy(IfaceType aidl_interface_type);
legacy_hal::wifi_multi_sta_use_case convertAidlMultiStaUseCaseToLegacy(
IWifiChip::MultiStaUseCase use_case);
bool convertAidlCoexUnsafeChannelToLegacy(
const IWifiChip::CoexUnsafeChannel& aidl_unsafe_channel,
legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
bool convertAidlVectorOfCoexUnsafeChannelToLegacy(
const std::vector<IWifiChip::CoexUnsafeChannel>& aidl_unsafe_channels,
std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
bool convertLegacyRadioCombinationsMatrixToAidl(
legacy_hal::wifi_radio_combination_matrix* legacy_matrix,
WifiRadioCombinationMatrix* aidl_matrix);
WifiBand convertLegacyMacBandToAidlWifiBand(uint32_t band);
WifiAntennaMode convertLegacyAntennaConfigurationToAidl(uint32_t antenna_cfg);
// STA iface conversion methods.
bool convertLegacyFeaturesToAidlStaCapabilities(uint64_t legacy_feature_set,
uint32_t legacy_logger_feature_set,
uint32_t* aidl_caps);
bool convertLegacyApfCapabilitiesToAidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
StaApfPacketFilterCapabilities* aidl_caps);
bool convertLegacyGscanCapabilitiesToAidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
StaBackgroundScanCapabilities* aidl_caps);
legacy_hal::wifi_band convertAidlWifiBandToLegacy(WifiBand band);
bool convertAidlGscanParamsToLegacy(const StaBackgroundScanParameters& aidl_scan_params,
legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
// Information Elements (IEs)
bool convertLegacyGscanResultToAidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
bool has_ie_data, StaScanResult* aidl_scan_result);
// |cached_results| is assumed to not include IEs.
bool convertLegacyVectorOfCachedGscanResultsToAidl(
const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
std::vector<StaScanData>* aidl_scan_datas);
bool convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats,
StaLinkLayerStats* aidl_stats);
bool convertLegacyRoamingCapabilitiesToAidl(
const legacy_hal::wifi_roaming_capabilities& legacy_caps,
StaRoamingCapabilities* aidl_caps);
bool convertAidlRoamingConfigToLegacy(const StaRoamingConfig& aidl_config,
legacy_hal::wifi_roaming_config* legacy_config);
legacy_hal::fw_roaming_state_t convertAidlRoamingStateToLegacy(StaRoamingState state);
bool convertLegacyVectorOfDebugTxPacketFateToAidl(
const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
std::vector<WifiDebugTxPacketFateReport>* aidl_fates);
bool convertLegacyVectorOfDebugRxPacketFateToAidl(
const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
std::vector<WifiDebugRxPacketFateReport>* aidl_fates);
// NAN iface conversion methods.
void convertToNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
NanStatus* nanStatus);
bool convertAidlNanEnableRequestToLegacy(const NanEnableRequest& aidl_request1,
const NanConfigRequestSupplemental& aidl_request2,
legacy_hal::NanEnableRequest* legacy_request);
bool convertAidlNanConfigRequestToLegacy(const NanConfigRequest& aidl_request1,
const NanConfigRequestSupplemental& aidl_request2,
legacy_hal::NanConfigRequest* legacy_request);
bool convertAidlNanPublishRequestToLegacy(const NanPublishRequest& aidl_request,
legacy_hal::NanPublishRequest* legacy_request);
bool convertAidlNanSubscribeRequestToLegacy(const NanSubscribeRequest& aidl_request,
legacy_hal::NanSubscribeRequest* legacy_request);
bool convertAidlNanTransmitFollowupRequestToLegacy(
const NanTransmitFollowupRequest& aidl_request,
legacy_hal::NanTransmitFollowupRequest* legacy_request);
bool convertAidlNanDataPathInitiatorRequestToLegacy(
const NanInitiateDataPathRequest& aidl_request,
legacy_hal::NanDataPathInitiatorRequest* legacy_request);
bool convertAidlNanDataPathIndicationResponseToLegacy(
const NanRespondToDataPathIndicationRequest& aidl_response,
legacy_hal::NanDataPathIndicationResponse* legacy_response);
bool convertLegacyNanResponseHeaderToAidl(const legacy_hal::NanResponseMsg& legacy_response,
NanStatus* nanStatus);
bool convertLegacyNanCapabilitiesResponseToAidl(const legacy_hal::NanCapabilities& legacy_response,
NanCapabilities* aidl_response);
bool convertLegacyNanMatchIndToAidl(const legacy_hal::NanMatchInd& legacy_ind,
NanMatchInd* aidl_ind);
bool convertLegacyNanFollowupIndToAidl(const legacy_hal::NanFollowupInd& legacy_ind,
NanFollowupReceivedInd* aidl_ind);
bool convertLegacyNanDataPathRequestIndToAidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
NanDataPathRequestInd* aidl_ind);
bool convertLegacyNanDataPathConfirmIndToAidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
NanDataPathConfirmInd* aidl_ind);
bool convertLegacyNanDataPathScheduleUpdateIndToAidl(
const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
NanDataPathScheduleUpdateInd* aidl_ind);
// RTT controller conversion methods.
bool convertAidlVectorOfRttConfigToLegacy(const std::vector<RttConfig>& aidl_configs,
std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
bool convertAidlRttLciInformationToLegacy(const RttLciInformation& aidl_info,
legacy_hal::wifi_lci_information* legacy_info);
bool convertAidlRttLcrInformationToLegacy(const RttLcrInformation& aidl_info,
legacy_hal::wifi_lcr_information* legacy_info);
bool convertAidlRttResponderToLegacy(const RttResponder& aidl_responder,
legacy_hal::wifi_rtt_responder* legacy_responder);
bool convertAidlWifiChannelInfoToLegacy(const WifiChannelInfo& aidl_info,
legacy_hal::wifi_channel_info* legacy_info);
bool convertLegacyRttResponderToAidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
RttResponder* aidl_responder);
bool convertLegacyRttCapabilitiesToAidl(
const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
RttCapabilities* aidl_capabilities);
bool convertLegacyVectorOfRttResultToAidl(
const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
std::vector<RttResult>* aidl_results);
uint32_t convertAidlWifiBandToLegacyMacBand(WifiBand band);
uint32_t convertAidlWifiIfaceModeToLegacy(uint32_t aidl_iface_mask);
uint32_t convertAidlUsableChannelFilterToLegacy(uint32_t aidl_filter_mask);
bool convertLegacyWifiUsableChannelsToAidl(
const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
std::vector<WifiUsableChannel>* aidl_usable_channels);
bool convertLegacyPeerInfoStatsToAidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
StaPeerInfo* aidl_peer_info_stats);
bool convertLegacyWifiRateInfoToAidl(const legacy_hal::wifi_rate& legacy_rate,
WifiRateInfo* aidl_rate);
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // AIDL_STRUCT_UTIL_H_

View File

@@ -0,0 +1,37 @@
/*
* 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 "aidl_sync_util.h"
namespace {
std::recursive_mutex g_mutex;
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace aidl_sync_util {
std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
return std::unique_lock<std::recursive_mutex>{g_mutex};
}
} // namespace aidl_sync_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,35 @@
/*
* 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.
*/
#ifndef AIDL_SYNC_UTIL_H_
#define AIDL_SYNC_UTIL_H_
#include <mutex>
// Utility that provides a global lock to synchronize access between
// the AIDL thread and the legacy HAL's event loop.
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace aidl_sync_util {
std::unique_lock<std::recursive_mutex> acquireGlobalLock();
} // namespace aidl_sync_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // AIDL_SYNC_UTIL_H_

View File

@@ -0,0 +1,8 @@
service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi-service-lazy
interface aidl android.hardware.wifi.IWifi/default
oneshot
disabled
class hal
capabilities NET_ADMIN NET_RAW SYS_MODULE
user wifi
group wifi gps

View File

@@ -0,0 +1,6 @@
service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi-service
interface aidl android.hardware.wifi.IWifi/default
class hal
capabilities NET_ADMIN NET_RAW SYS_MODULE
user wifi
group wifi gps

View File

@@ -0,0 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.wifi</name>
<fqname>IWifi/default</fqname>
</hal>
</manifest>

View File

@@ -0,0 +1,62 @@
/*
* 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 "ringbuffer.h"
#include <android-base/logging.h>
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
enum Ringbuffer::AppendStatus Ringbuffer::append(const std::vector<uint8_t>& input) {
if (input.size() == 0) {
return AppendStatus::FAIL_IP_BUFFER_ZERO;
}
if (input.size() > maxSize_) {
LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped";
return AppendStatus::FAIL_IP_BUFFER_EXCEEDED_MAXSIZE;
}
data_.push_back(input);
size_ += input.size() * sizeof(input[0]);
while (size_ > maxSize_) {
if (data_.front().size() <= 0 || data_.front().size() > maxSize_) {
LOG(ERROR) << "First buffer in the ring buffer is Invalid. Size: "
<< data_.front().size();
return AppendStatus::FAIL_RING_BUFFER_CORRUPTED;
}
size_ -= data_.front().size() * sizeof(data_.front()[0]);
data_.pop_front();
}
return AppendStatus::SUCCESS;
}
const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
return data_;
}
void Ringbuffer::clear() {
data_.clear();
size_ = 0;
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,60 @@
/*
* 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.
*/
#ifndef RINGBUFFER_H_
#define RINGBUFFER_H_
#include <list>
#include <vector>
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* Ringbuffer object used to store debug data.
*/
class Ringbuffer {
public:
// Error codes for the append ring buffer operation
enum AppendStatus {
SUCCESS,
FAIL_GENERIC,
FAIL_IP_BUFFER_ZERO,
FAIL_IP_BUFFER_EXCEEDED_MAXSIZE,
FAIL_RING_BUFFER_CORRUPTED
};
explicit Ringbuffer(size_t maxSize);
// Appends the data buffer and deletes from the front until buffer is
// within |maxSize_|.
enum AppendStatus append(const std::vector<uint8_t>& input);
const std::list<std::vector<uint8_t>>& getData() const;
void clear();
private:
std::list<std::vector<uint8_t>> data_;
size_t size_;
size_t maxSize_;
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // RINGBUFFER_H_

View File

@@ -0,0 +1,73 @@
/*
* 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 <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <signal.h>
#include "wifi.h"
#include "wifi_feature_flags.h"
#include "wifi_legacy_hal.h"
#include "wifi_legacy_hal_factory.h"
#include "wifi_mode_controller.h"
using aidl::android::hardware::wifi::feature_flags::WifiFeatureFlags;
using aidl::android::hardware::wifi::legacy_hal::WifiLegacyHal;
using aidl::android::hardware::wifi::legacy_hal::WifiLegacyHalFactory;
using aidl::android::hardware::wifi::mode_controller::WifiModeController;
#ifdef LAZY_SERVICE
const bool kLazyService = true;
#else
const bool kLazyService = false;
#endif
int main(int /*argc*/, char** argv) {
signal(SIGPIPE, SIG_IGN);
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Wifi Hal is booting up...";
// Prepare the RPC-serving thread pool. Allocate 1 thread in the pool,
// which our main thread will join below.
ABinderProcess_setThreadPoolMaxThreadCount(1);
const auto iface_tool = std::make_shared<::android::wifi_system::InterfaceTool>();
const auto legacy_hal_factory = std::make_shared<WifiLegacyHalFactory>(iface_tool);
// Setup binder service
std::shared_ptr<aidl::android::hardware::wifi::Wifi> service =
ndk::SharedRefBase::make<aidl::android::hardware::wifi::Wifi>(
iface_tool, legacy_hal_factory, std::make_shared<WifiModeController>(),
std::make_shared<WifiFeatureFlags>());
std::string instance =
std::string() + aidl::android::hardware::wifi::Wifi::descriptor + "/default";
if (kLazyService) {
auto result =
AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str());
CHECK_EQ(result, STATUS_OK) << "Failed to register lazy wifi HAL";
} else {
auto result = AServiceManager_addService(service->asBinder().get(), instance.c_str());
CHECK_EQ(result, STATUS_OK) << "Failed to register wifi HAL";
}
ABinderProcess_startThreadPool();
LOG(INFO) << "Joining RPC thread pool";
ABinderProcess_joinThreadPool();
LOG(INFO) << "Wifi Hal is terminating...";
return 0;
}

View File

@@ -0,0 +1,485 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <gmock/gmock.h>
#include "aidl_struct_util.h"
using testing::Test;
namespace {
constexpr uint32_t kMacId1 = 1;
constexpr uint32_t kMacId2 = 2;
constexpr uint32_t kIfaceChannel1 = 3;
constexpr uint32_t kIfaceChannel2 = 5;
constexpr char kIfaceName1[] = "wlan0";
constexpr char kIfaceName2[] = "wlan1";
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
class AidlStructUtilTest : public Test {};
TEST_F(AidlStructUtilTest, CanConvertLegacyWifiMacInfosToAidlWithOneMac) {
std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
legacy_hal::WifiMacInfo legacy_mac_info1 = {
.wlan_mac_id = kMacId1,
.mac_band = legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
legacy_mac_infos.push_back(legacy_mac_info1);
std::vector<IWifiChipEventCallback::RadioModeInfo> aidl_radio_mode_infos;
ASSERT_TRUE(aidl_struct_util::convertLegacyWifiMacInfosToAidl(legacy_mac_infos,
&aidl_radio_mode_infos));
ASSERT_EQ(1u, aidl_radio_mode_infos.size());
auto aidl_radio_mode_info1 = aidl_radio_mode_infos[0];
EXPECT_EQ(legacy_mac_info1.wlan_mac_id, (uint32_t)aidl_radio_mode_info1.radioId);
EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, aidl_radio_mode_info1.bandInfo);
ASSERT_EQ(2u, aidl_radio_mode_info1.ifaceInfos.size());
auto aidl_iface_info1 = aidl_radio_mode_info1.ifaceInfos[0];
EXPECT_EQ(legacy_iface_info1.name, aidl_iface_info1.name);
EXPECT_EQ(static_cast<int32_t>(legacy_iface_info1.channel), aidl_iface_info1.channel);
auto aidl_iface_info2 = aidl_radio_mode_info1.ifaceInfos[1];
EXPECT_EQ(legacy_iface_info2.name, aidl_iface_info2.name);
EXPECT_EQ(static_cast<int32_t>(legacy_iface_info2.channel), aidl_iface_info2.channel);
}
TEST_F(AidlStructUtilTest, CanConvertLegacyWifiMacInfosToAidlWithTwoMac) {
std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
legacy_hal::WifiMacInfo legacy_mac_info1 = {.wlan_mac_id = kMacId1,
.mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
legacy_hal::WifiMacInfo legacy_mac_info2 = {.wlan_mac_id = kMacId2,
.mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
legacy_mac_infos.push_back(legacy_mac_info1);
legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
legacy_mac_infos.push_back(legacy_mac_info2);
std::vector<IWifiChipEventCallback::RadioModeInfo> aidl_radio_mode_infos;
ASSERT_TRUE(aidl_struct_util::convertLegacyWifiMacInfosToAidl(legacy_mac_infos,
&aidl_radio_mode_infos));
ASSERT_EQ(2u, aidl_radio_mode_infos.size());
// Find mac info 1.
const auto aidl_radio_mode_info1 =
std::find_if(aidl_radio_mode_infos.begin(), aidl_radio_mode_infos.end(),
[&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
return (uint32_t)x.radioId == legacy_mac_info1.wlan_mac_id;
});
ASSERT_NE(aidl_radio_mode_infos.end(), aidl_radio_mode_info1);
EXPECT_EQ(WifiBand::BAND_5GHZ, aidl_radio_mode_info1->bandInfo);
ASSERT_EQ(1u, aidl_radio_mode_info1->ifaceInfos.size());
auto aidl_iface_info1 = aidl_radio_mode_info1->ifaceInfos[0];
EXPECT_EQ(legacy_iface_info1.name, aidl_iface_info1.name);
EXPECT_EQ(static_cast<int32_t>(legacy_iface_info1.channel), aidl_iface_info1.channel);
// Find mac info 2.
const auto aidl_radio_mode_info2 =
std::find_if(aidl_radio_mode_infos.begin(), aidl_radio_mode_infos.end(),
[&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
return (uint32_t)x.radioId == legacy_mac_info2.wlan_mac_id;
});
ASSERT_NE(aidl_radio_mode_infos.end(), aidl_radio_mode_info2);
EXPECT_EQ(WifiBand::BAND_24GHZ, aidl_radio_mode_info2->bandInfo);
ASSERT_EQ(1u, aidl_radio_mode_info2->ifaceInfos.size());
auto aidl_iface_info2 = aidl_radio_mode_info2->ifaceInfos[0];
EXPECT_EQ(legacy_iface_info2.name, aidl_iface_info2.name);
EXPECT_EQ(static_cast<int32_t>(legacy_iface_info2.channel), aidl_iface_info2.channel);
}
TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerStatsToAidl) {
legacy_hal::LinkLayerStats legacy_stats{};
legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
legacy_stats.iface.beacon_rx = rand();
legacy_stats.iface.rssi_mgmt = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples = rand();
legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
legacy_stats.iface.num_peers = 1;
for (auto& radio : legacy_stats.radios) {
radio.stats.radio = rand();
radio.stats.on_time = rand();
radio.stats.tx_time = rand();
radio.stats.rx_time = rand();
radio.stats.on_time_scan = rand();
radio.stats.on_time_nbd = rand();
radio.stats.on_time_gscan = rand();
radio.stats.on_time_roam_scan = rand();
radio.stats.on_time_pno_scan = rand();
radio.stats.on_time_hs20 = rand();
for (int i = 0; i < 4; i++) {
radio.tx_time_per_levels.push_back(rand());
}
legacy_hal::wifi_channel_stat channel_stat1 = {
.channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
.on_time = 0x1111,
.cca_busy_time = 0x55,
};
legacy_hal::wifi_channel_stat channel_stat2 = {
.channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
.on_time = 0x2222,
.cca_busy_time = 0x66,
};
radio.channel_stats.push_back(channel_stat1);
radio.channel_stats.push_back(channel_stat2);
}
for (auto& peer : legacy_stats.peers) {
peer.peer_info.bssload.sta_count = rand();
peer.peer_info.bssload.chan_util = rand();
wifi_rate_stat rate_stat1 = {
.rate = {3, 1, 2, 5, 0, 0},
.tx_mpdu = 0,
.rx_mpdu = 1,
.mpdu_lost = 2,
.retries = 3,
.retries_short = 4,
.retries_long = 5,
};
wifi_rate_stat rate_stat2 = {
.rate = {2, 2, 1, 6, 0, 1},
.tx_mpdu = 6,
.rx_mpdu = 7,
.mpdu_lost = 8,
.retries = 9,
.retries_short = 10,
.retries_long = 11,
};
peer.rate_stats.push_back(rate_stat1);
peer.rate_stats.push_back(rate_stat2);
}
StaLinkLayerStats converted{};
aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &converted);
EXPECT_EQ(legacy_stats.iface.beacon_rx, (uint32_t)converted.iface.beaconRx);
EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
converted.iface.wmeBePktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
converted.iface.wmeBePktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
converted.iface.wmeBePktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
converted.iface.wmeBePktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
(uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
(uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
(uint32_t)converted.iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
(uint32_t)converted.iface.wmeBeContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
converted.iface.wmeBkPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
converted.iface.wmeBkPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
converted.iface.wmeBkPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
converted.iface.wmeBkPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
(uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
(uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
(uint32_t)converted.iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
(uint32_t)converted.iface.wmeBkContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
converted.iface.wmeViPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
converted.iface.wmeViPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
converted.iface.wmeViPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
converted.iface.wmeViPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
(uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
(uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
(uint32_t)converted.iface.wmeViContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
(uint32_t)converted.iface.wmeViContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
converted.iface.wmeVoPktStats.rxMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
converted.iface.wmeVoPktStats.txMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
converted.iface.wmeVoPktStats.lostMpdu);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
converted.iface.wmeVoPktStats.retries);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
(uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMinInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
(uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
(uint32_t)converted.iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec);
EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
(uint32_t)converted.iface.wmeVoContentionTimeStats.contentionNumSamples);
EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
converted.iface.timeSliceDutyCycleInPercent);
EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
EXPECT_EQ(legacy_stats.radios[i].stats.radio, converted.radios[i].radioId);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time, (uint32_t)converted.radios[i].onTimeInMs);
EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, (uint32_t)converted.radios[i].txTimeInMs);
EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, (uint32_t)converted.radios[i].rxTimeInMs);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
(uint32_t)converted.radios[i].onTimeInMsForScan);
EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
converted.radios[i].txTimeInMsPerLevel.size());
for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size(); j++) {
EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
(uint32_t)converted.radios[i].txTimeInMsPerLevel[j]);
}
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
(uint32_t)converted.radios[i].onTimeInMsForNanScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
(uint32_t)converted.radios[i].onTimeInMsForBgScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
(uint32_t)converted.radios[i].onTimeInMsForRoamScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
(uint32_t)converted.radios[i].onTimeInMsForPnoScan);
EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
(uint32_t)converted.radios[i].onTimeInMsForHs20Scan);
EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
converted.radios[i].channelStats.size());
for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size(); k++) {
auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
converted.radios[i].channelStats[k].channel.width);
EXPECT_EQ(legacy_channel_st.channel.center_freq,
converted.radios[i].channelStats[k].channel.centerFreq);
EXPECT_EQ(legacy_channel_st.channel.center_freq0,
converted.radios[i].channelStats[k].channel.centerFreq0);
EXPECT_EQ(legacy_channel_st.channel.center_freq1,
converted.radios[i].channelStats[k].channel.centerFreq1);
EXPECT_EQ(legacy_channel_st.cca_busy_time,
(uint32_t)converted.radios[i].channelStats[k].ccaBusyTimeInMs);
EXPECT_EQ(legacy_channel_st.on_time,
(uint32_t)converted.radios[i].channelStats[k].onTimeInMs);
}
}
EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size());
for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
converted.iface.peers[i].staCount);
EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
converted.iface.peers[i].chanUtil);
for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
(uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.preamble);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss,
(uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw,
(uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
(uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
(uint32_t)converted.iface.peers[i].rateStats[j].txMpdu);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
(uint32_t)converted.iface.peers[i].rateStats[j].rxMpdu);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
(uint32_t)converted.iface.peers[i].rateStats[j].mpduLost);
EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
(uint32_t)converted.iface.peers[i].rateStats[j].retries);
}
}
}
TEST_F(AidlStructUtilTest, CanConvertLegacyFeaturesToAidl) {
using AidlChipCaps = IWifiChip::ChipCapabilityMask;
uint32_t aidl_caps;
uint32_t legacy_feature_set = WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
uint32_t legacy_logger_feature_set = legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
ASSERT_TRUE(aidl_struct_util::convertLegacyFeaturesToAidlChipCapabilities(
legacy_feature_set, legacy_logger_feature_set, &aidl_caps));
EXPECT_EQ((uint32_t)AidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
(uint32_t)AidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
(uint32_t)AidlChipCaps::DEBUG_ERROR_ALERTS | (uint32_t)AidlChipCaps::D2D_RTT |
(uint32_t)AidlChipCaps::SET_LATENCY_MODE |
(uint32_t)AidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
aidl_caps);
}
void insertRadioCombination(legacy_hal::wifi_radio_combination* dst_radio_combination_ptr,
int num_radio_configurations,
legacy_hal::wifi_radio_configuration* radio_configuration) {
dst_radio_combination_ptr->num_radio_configurations = num_radio_configurations;
memcpy(dst_radio_combination_ptr->radio_configurations, radio_configuration,
num_radio_configurations * sizeof(legacy_hal::wifi_radio_configuration));
}
void verifyRadioCombination(WifiRadioCombination* radioCombination, size_t num_radio_configurations,
legacy_hal::wifi_radio_configuration* radio_configuration) {
EXPECT_EQ(num_radio_configurations, radioCombination->radioConfigurations.size());
for (size_t i = 0; i < num_radio_configurations; i++) {
EXPECT_EQ(aidl_struct_util::convertLegacyMacBandToAidlWifiBand(radio_configuration->band),
radioCombination->radioConfigurations[i].bandInfo);
EXPECT_EQ(aidl_struct_util::convertLegacyAntennaConfigurationToAidl(
radio_configuration->antenna_cfg),
radioCombination->radioConfigurations[i].antennaMode);
radio_configuration++;
}
}
TEST_F(AidlStructUtilTest, canConvertLegacyRadioCombinationsMatrixToAidl) {
legacy_hal::wifi_radio_configuration radio_configurations_array1[] = {
{.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1},
};
legacy_hal::wifi_radio_configuration radio_configurations_array2[] = {
{.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2},
{.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_3X3},
};
legacy_hal::wifi_radio_configuration radio_configurations_array3[] = {
{.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2},
{.band = legacy_hal::WLAN_MAC_6_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1},
{.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_4X4},
};
int num_radio_configs = 0;
int num_combinations = 0;
std::array<char, 256> buffer;
buffer.fill(0);
legacy_hal::wifi_radio_combination_matrix* legacy_matrix =
reinterpret_cast<wifi_radio_combination_matrix*>(buffer.data());
legacy_hal::wifi_radio_combination* radio_combinations;
// Prepare a legacy wifi_radio_combination_matrix
legacy_matrix->num_radio_combinations = 3;
// Insert first combination
radio_combinations =
(legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations);
insertRadioCombination(
radio_combinations,
sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]),
radio_configurations_array1);
num_combinations++;
num_radio_configs +=
sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]);
// Insert second combination
radio_combinations =
(legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations +
(num_combinations *
sizeof(legacy_hal::wifi_radio_combination)) +
(num_radio_configs *
sizeof(wifi_radio_configuration)));
insertRadioCombination(
radio_combinations,
sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]),
radio_configurations_array2);
num_combinations++;
num_radio_configs +=
sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]);
// Insert third combination
radio_combinations =
(legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations +
(num_combinations *
sizeof(legacy_hal::wifi_radio_combination)) +
(num_radio_configs *
sizeof(wifi_radio_configuration)));
insertRadioCombination(
radio_combinations,
sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]),
radio_configurations_array3);
WifiRadioCombinationMatrix converted_matrix{};
aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix, &converted_matrix);
// Verify the conversion
EXPECT_EQ(legacy_matrix->num_radio_combinations, converted_matrix.radioCombinations.size());
verifyRadioCombination(
&converted_matrix.radioCombinations[0],
sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]),
radio_configurations_array1);
verifyRadioCombination(
&converted_matrix.radioCombinations[1],
sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]),
radio_configurations_array2);
verifyRadioCombination(
&converted_matrix.radioCombinations[2],
sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]),
radio_configurations_array3);
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,28 @@
/*
* 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <android-base/logging.h>
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::InitGoogleMock(&argc, argv);
// Force ourselves to always log to stderr
android::base::InitLogging(argv, android::base::StderrLogger);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,28 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <gmock/gmock.h>
#include "mock_interface_tool.h"
namespace android {
namespace wifi_system {
MockInterfaceTool::MockInterfaceTool() {}
} // namespace wifi_system
} // namespace android

View File

@@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef MOCK_INTERFACE_TOOL_H
#define MOCK_INTERFACE_TOOL_H
#include <gmock/gmock.h>
#include <wifi_system/interface_tool.h>
namespace android {
namespace wifi_system {
class MockInterfaceTool : public InterfaceTool {
public:
MockInterfaceTool();
MOCK_METHOD1(GetUpState, bool(const char* if_name));
MOCK_METHOD2(SetUpState, bool(const char* if_name, bool request_up));
MOCK_METHOD1(SetWifiUpState, bool(bool request_up));
MOCK_METHOD2(SetMacAddress,
bool(const char* if_name, const std::array<uint8_t, ETH_ALEN>& address));
MOCK_METHOD1(GetFactoryMacAddress, std::array<uint8_t, ETH_ALEN>(const char* if_name));
}; // class MockInterfaceTool
} // namespace wifi_system
} // namespace android
#endif // MOCK_INTERFACE_TOOL_H

View File

@@ -0,0 +1,33 @@
/*
* 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 <gmock/gmock.h>
#include "mock_wifi_feature_flags.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace feature_flags {
MockWifiFeatureFlags::MockWifiFeatureFlags() {}
} // namespace feature_flags
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,44 @@
/*
* 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.
*/
#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
#define MOCK_WIFI_FEATURE_FLAGS_H_
#include <gmock/gmock.h>
#include "wifi_feature_flags.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace feature_flags {
class MockWifiFeatureFlags : public WifiFeatureFlags {
public:
MockWifiFeatureFlags();
MOCK_METHOD1(getChipModes, std::vector<IWifiChip::ChipMode>(bool is_primary));
MOCK_METHOD0(isApMacRandomizationDisabled, bool());
};
} // namespace feature_flags
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // MOCK_WIFI_FEATURE_FLAGS_H_

View File

@@ -0,0 +1,38 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <gmock/gmock.h>
#include "mock_wifi_iface_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace iface_util {
MockWifiIfaceUtil::MockWifiIfaceUtil(
const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
: WifiIfaceUtil(iface_tool, legacy_hal) {}
} // namespace iface_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,50 @@
/*
* 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.
*/
#ifndef MOCK_WIFI_IFACE_UTIL_H_
#define MOCK_WIFI_IFACE_UTIL_H_
#include <gmock/gmock.h>
#include "wifi_iface_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace iface_util {
class MockWifiIfaceUtil : public iface_util::WifiIfaceUtil {
public:
MockWifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
MOCK_METHOD1(getFactoryMacAddress, std::array<uint8_t, 6>(const std::string&));
MOCK_METHOD2(setMacAddress, bool(const std::string&, const std::array<uint8_t, 6>&));
MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
MOCK_METHOD2(registerIfaceEventHandlers,
void(const std::string&, iface_util::IfaceEventHandlers));
MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
MOCK_METHOD2(setUpState, bool(const std::string&, bool));
MOCK_METHOD1(ifNameToIndex, unsigned(const std::string&));
};
} // namespace iface_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // MOCK_WIFI_IFACE_UTIL_H_

View File

@@ -0,0 +1,37 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <gmock/gmock.h>
#include "mock_wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace legacy_hal {
MockWifiLegacyHal::MockWifiLegacyHal(
const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const wifi_hal_fn& fn, bool is_primary)
: WifiLegacyHal(iface_tool, fn, is_primary) {}
} // namespace legacy_hal
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,69 @@
/*
* 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.
*/
#ifndef MOCK_WIFI_LEGACY_HAL_H_
#define MOCK_WIFI_LEGACY_HAL_H_
#include <gmock/gmock.h>
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace legacy_hal {
class MockWifiLegacyHal : public WifiLegacyHal {
public:
MockWifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const wifi_hal_fn& fn, bool is_primary);
MOCK_METHOD0(initialize, wifi_error());
MOCK_METHOD0(start, wifi_error());
MOCK_METHOD2(stop,
wifi_error(std::unique_lock<std::recursive_mutex>*, const std::function<void()>&));
MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
wifi_error(const std::string&, const on_radio_mode_change_callback&));
MOCK_METHOD1(getFirmwareVersion,
std::pair<wifi_error, std::string>(const std::string& iface_name));
MOCK_METHOD1(getDriverVersion,
std::pair<wifi_error, std::string>(const std::string& iface_name));
MOCK_METHOD2(selectTxPowerScenario,
wifi_error(const std::string& iface_name, wifi_power_scenario scenario));
MOCK_METHOD1(resetTxPowerScenario, wifi_error(const std::string& iface_name));
MOCK_METHOD2(nanRegisterCallbackHandlers,
wifi_error(const std::string&, const NanCallbackHandlers&));
MOCK_METHOD2(nanDisableRequest, wifi_error(const std::string&, transaction_id));
MOCK_METHOD3(nanDataInterfaceDelete,
wifi_error(const std::string&, transaction_id, const std::string&));
MOCK_METHOD2(createVirtualInterface,
wifi_error(const std::string& ifname, wifi_interface_type iftype));
MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname));
MOCK_METHOD0(waitForDriverReady, wifi_error());
MOCK_METHOD2(getSupportedIfaceName, wifi_error(uint32_t, std::string&));
MOCK_METHOD1(registerSubsystemRestartCallbackHandler,
wifi_error(const on_subsystem_restart_callback&));
MOCK_METHOD1(getSupportedFeatureSet, std::pair<wifi_error, uint64_t>(const std::string&));
};
} // namespace legacy_hal
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // MOCK_WIFI_LEGACY_HAL_H_

View File

@@ -0,0 +1,36 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <gmock/gmock.h>
#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38
#include "mock_wifi_mode_controller.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace mode_controller {
MockWifiModeController::MockWifiModeController() : WifiModeController() {}
} // namespace mode_controller
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,44 @@
/*
* 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.
*/
#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
#define MOCK_WIFI_MODE_CONTROLLER_H_
#include <gmock/gmock.h>
#include "wifi_mode_controller.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace mode_controller {
class MockWifiModeController : public WifiModeController {
public:
MockWifiModeController();
MOCK_METHOD0(initialize, bool());
MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
MOCK_METHOD0(deinitialize, bool());
};
} // namespace mode_controller
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // MOCK_WIFI_MODE_CONTROLLER_H_

View File

@@ -0,0 +1,96 @@
/*
* 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 <gmock/gmock.h>
#include "ringbuffer.h"
using testing::Return;
using testing::Test;
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
class RingbufferTest : public Test {
public:
const uint32_t maxBufferSize_ = 10;
Ringbuffer buffer_{maxBufferSize_};
};
TEST_F(RingbufferTest, CreateEmptyBuffer) {
ASSERT_TRUE(buffer_.getData().empty());
}
TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
buffer_.append(input);
buffer_.append(input2);
ASSERT_EQ(2u, buffer_.getData().size());
EXPECT_EQ(input, buffer_.getData().front());
EXPECT_EQ(input2, buffer_.getData().back());
}
TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
const std::vector<uint8_t> input3 = {'G'};
buffer_.append(input);
buffer_.append(input2);
buffer_.append(input3);
ASSERT_EQ(2u, buffer_.getData().size());
EXPECT_EQ(input2, buffer_.getData().front());
EXPECT_EQ(input3, buffer_.getData().back());
}
TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
const std::vector<uint8_t> input3(maxBufferSize_, '2');
buffer_.append(input);
buffer_.append(input2);
buffer_.append(input3);
ASSERT_EQ(1u, buffer_.getData().size());
EXPECT_EQ(input3, buffer_.getData().front());
}
TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
const std::vector<uint8_t> input = {};
buffer_.append(input);
ASSERT_TRUE(buffer_.getData().empty());
}
TEST_F(RingbufferTest, OversizedAppendIsDropped) {
const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
buffer_.append(input);
ASSERT_TRUE(buffer_.getData().empty());
}
TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
const std::vector<uint8_t> input(maxBufferSize_, '0');
const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
buffer_.append(input);
buffer_.append(input2);
ASSERT_EQ(1u, buffer_.getData().size());
EXPECT_EQ(input, buffer_.getData().front());
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# 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.
if [ -z $ANDROID_BUILD_TOP ]; then
echo "You need to source and lunch before you can use this script"
exit 1
fi
set -e
$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode android.hardware.wifi-service-tests
adb root
adb sync data
adb shell /data/nativetest64/vendor/android.hardware.wifi-service-tests/android.hardware.wifi-service-tests

View File

@@ -0,0 +1,855 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <cutils/properties.h>
#include <gmock/gmock.h>
#include "wifi_chip.h"
#include "mock_interface_tool.h"
#include "mock_wifi_feature_flags.h"
#include "mock_wifi_iface_util.h"
#include "mock_wifi_legacy_hal.h"
#include "mock_wifi_mode_controller.h"
using testing::NiceMock;
using testing::Return;
using testing::Test;
namespace {
constexpr int kFakeChipId = 5;
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
class WifiChipTest : public Test {
protected:
void setupV1IfaceCombination() {
// clang-format off
// 1 STA + 1 P2P
const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsSta =
{
{
{
{{IfaceConcurrencyType::STA}, 1},
{{IfaceConcurrencyType::P2P}, 1}
}
}
};
// 1 AP
const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsAp =
{
{
{
{{IfaceConcurrencyType::AP}, 1}
}
}
};
const std::vector<IWifiChip::ChipMode> modes = {
{feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
{feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
};
// clang-format on
EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
}
void setupV1_AwareIfaceCombination() {
// clang-format off
// 1 STA + 1 of (P2P or NAN)
const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsSta =
{
{
{
{{IfaceConcurrencyType::STA}, 1},
{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
}
}
};
// 1 AP
const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsAp =
{
{
{
{{IfaceConcurrencyType::AP}, 1}
}
}
};
const std::vector<IWifiChip::ChipMode> modes = {
{feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
{feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
};
// clang-format on
EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
}
void setupV1_AwareDisabledApIfaceCombination() {
// clang-format off
// 1 STA + 1 of (P2P or NAN)
const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsSta =
{
{
{
{{IfaceConcurrencyType::STA}, 1},
{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
}
}
};
const std::vector<IWifiChip::ChipMode> modes = {
{feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
};
// clang-format on
EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
}
void setupV2_AwareIfaceCombination() {
// clang-format off
// (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
const std::vector<IWifiChip::ChipConcurrencyCombination> combinations =
{
{
{
{{IfaceConcurrencyType::STA}, 1},
{{IfaceConcurrencyType::AP}, 1}
}
},
{
{
{{IfaceConcurrencyType::STA}, 1},
{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
}
}
};
const std::vector<IWifiChip::ChipMode> modes = {
{feature_flags::chip_mode_ids::kV3, combinations}
};
// clang-format on
EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
}
void setupV2_AwareDisabledApIfaceCombination() {
// clang-format off
// 1 STA + 1 of (P2P or NAN)
const std::vector<IWifiChip::ChipConcurrencyCombination> combinations =
{
{
{
{{IfaceConcurrencyType::STA}, 1},
{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
}
}
};
const std::vector<IWifiChip::ChipMode> modes = {
{feature_flags::chip_mode_ids::kV3, combinations}
};
// clang-format on
EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
}
void setup_MultiIfaceCombination() {
// clang-format off
// 3 STA + 1 AP
const std::vector<IWifiChip::ChipConcurrencyCombination> combinations =
{
{
{
{{IfaceConcurrencyType::STA}, 3},
{{IfaceConcurrencyType::AP}, 1}
}
}
};
const std::vector<IWifiChip::ChipMode> modes = {
{feature_flags::chip_mode_ids::kV3, combinations}
};
// clang-format on
EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
}
void assertNumberOfModes(uint32_t num_modes) {
std::vector<IWifiChip::ChipMode> modes;
ASSERT_TRUE(chip_->getAvailableModes(&modes).isOk());
// V2_Aware has 1 mode of operation.
ASSERT_EQ(num_modes, modes.size());
}
void findModeAndConfigureForIfaceType(const IfaceConcurrencyType& type) {
// This should be aligned with kInvalidModeId in wifi_chip.cpp
int32_t mode_id = INT32_MAX;
std::vector<IWifiChip::ChipMode> modes;
ASSERT_TRUE(chip_->getAvailableModes(&modes).isOk());
for (const auto& mode : modes) {
for (const auto& combination : mode.availableCombinations) {
for (const auto& limit : combination.limits) {
if (limit.types.end() !=
std::find(limit.types.begin(), limit.types.end(), type)) {
mode_id = mode.id;
}
}
}
}
ASSERT_NE(INT32_MAX, mode_id);
ASSERT_TRUE(chip_->configureChip(mode_id).isOk());
}
// Returns an empty string on error.
std::string createIface(const IfaceType& type) {
std::string iface_name;
if (type == IfaceType::AP) {
std::shared_ptr<IWifiApIface> iface;
if (!chip_->createApIface(&iface).isOk()) {
return "";
}
EXPECT_NE(iface.get(), nullptr);
EXPECT_TRUE(iface->getName(&iface_name).isOk());
} else if (type == IfaceType::NAN_IFACE) {
std::shared_ptr<IWifiNanIface> iface;
if (!chip_->createNanIface(&iface).isOk()) {
return "";
}
EXPECT_NE(iface.get(), nullptr);
EXPECT_TRUE(iface->getName(&iface_name).isOk());
} else if (type == IfaceType::P2P) {
std::shared_ptr<IWifiP2pIface> iface;
if (!chip_->createP2pIface(&iface).isOk()) {
return "";
}
EXPECT_NE(iface.get(), nullptr);
EXPECT_TRUE(iface->getName(&iface_name).isOk());
} else if (type == IfaceType::STA) {
std::shared_ptr<IWifiStaIface> iface;
if (!chip_->createStaIface(&iface).isOk()) {
return "";
}
EXPECT_NE(iface.get(), nullptr);
EXPECT_TRUE(iface->getName(&iface_name).isOk());
}
return iface_name;
}
void removeIface(const IfaceType& type, const std::string& iface_name) {
if (type == IfaceType::AP) {
ASSERT_TRUE(chip_->removeApIface(iface_name).isOk());
} else if (type == IfaceType::NAN_IFACE) {
ASSERT_TRUE(chip_->removeNanIface(iface_name).isOk());
} else if (type == IfaceType::P2P) {
ASSERT_TRUE(chip_->removeP2pIface(iface_name).isOk());
} else if (type == IfaceType::STA) {
ASSERT_TRUE(chip_->removeStaIface(iface_name).isOk());
}
}
bool createRttController() {
std::shared_ptr<IWifiRttController> rtt_controller;
auto status = chip_->createRttController(nullptr, &rtt_controller);
return status.isOk();
}
static void subsystemRestartHandler(const std::string& /*error*/) {}
std::shared_ptr<WifiChip> chip_;
int chip_id_ = kFakeChipId;
legacy_hal::wifi_hal_fn fake_func_table_;
std::shared_ptr<NiceMock<::android::wifi_system::MockInterfaceTool>> iface_tool_{
new NiceMock<::android::wifi_system::MockInterfaceTool>};
std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>> mode_controller_{
new NiceMock<mode_controller::MockWifiModeController>};
std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>> feature_flags_{
new NiceMock<feature_flags::MockWifiFeatureFlags>};
public:
void SetUp() override {
chip_ = WifiChip::create(chip_id_, true, legacy_hal_, mode_controller_, iface_util_,
feature_flags_, subsystemRestartHandler);
EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(*legacy_hal_, start())
.WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
// Vendor HAL does not override the name by default.
EXPECT_CALL(*legacy_hal_, getSupportedIfaceName(testing::_, testing::_))
.WillRepeatedly(testing::Return(legacy_hal::WIFI_ERROR_UNKNOWN));
}
void TearDown() override {
// Restore default system iface names (This should ideally be using a
// mock).
property_set("wifi.interface", "wlan0");
property_set("wifi.concurrent.interface", "wlan1");
property_set("wifi.aware.interface", nullptr);
}
};
////////// V1 Iface Combinations ////////////
// Mode 1 - STA + P2P
// Mode 2 - AP
class WifiChipV1IfaceCombinationTest : public WifiChipTest {
public:
void SetUp() override {
setupV1IfaceCombination();
WifiChipTest::SetUp();
// V1 has 2 modes of operation.
assertNumberOfModes(2);
}
};
TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
}
TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_TRUE(createIface(IfaceType::AP).empty());
}
TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
}
TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_TRUE(createIface(IfaceType::STA).empty());
}
TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_TRUE(createIface(IfaceType::STA).empty());
}
TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
}
////////// V1 + Aware Iface Combinations ////////////
// Mode 1 - STA + P2P/NAN
// Mode 2 - AP
class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
public:
void SetUp() override {
setupV1_AwareIfaceCombination();
WifiChipTest::SetUp();
// V1_Aware has 2 modes of operation.
assertNumberOfModes(2u);
}
};
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_TRUE(createIface(IfaceType::AP).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2PNan_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
std::string p2p_iface_name = createIface(IfaceType::P2P);
ASSERT_FALSE(p2p_iface_name.empty());
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
// After removing P2P iface, NAN iface creation should succeed.
removeIface(IfaceType::P2P, p2p_iface_name);
ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
std::string nan_iface_name = createIface(IfaceType::NAN_IFACE);
ASSERT_FALSE(nan_iface_name.empty());
ASSERT_TRUE(createIface(IfaceType::P2P).empty());
// After removing NAN iface, P2P iface creation should succeed.
removeIface(IfaceType::NAN_IFACE, nan_iface_name);
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_TRUE(createIface(IfaceType::STA).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_TRUE(createIface(IfaceType::STA).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_TRUE(createRttController());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_TRUE(createRttController());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
std::string ap_iface_name = createIface(IfaceType::AP);
ASSERT_FALSE(ap_iface_name.empty());
ASSERT_FALSE(createRttController());
removeIface(IfaceType::AP, ap_iface_name);
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_TRUE(createRttController());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
.WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
}
TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
.WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
}
////////// V2 + Aware Iface Combinations ////////////
// Mode 1 - STA + STA/AP
// - STA + P2P/NAN
class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
public:
void SetUp() override {
setupV2_AwareIfaceCombination();
WifiChipTest::SetUp();
// V2_Aware has 1 mode of operation.
assertNumberOfModes(1u);
}
};
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
ASSERT_TRUE(createIface(IfaceType::STA).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_AfterStaApRemove_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
std::string sta_iface_name = createIface(IfaceType::STA);
ASSERT_FALSE(sta_iface_name.empty());
std::string ap_iface_name = createIface(IfaceType::AP);
ASSERT_FALSE(ap_iface_name.empty());
ASSERT_TRUE(createIface(IfaceType::STA).empty());
// After removing AP & STA iface, STA iface creation should succeed.
removeIface(IfaceType::STA, sta_iface_name);
removeIface(IfaceType::AP, ap_iface_name);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_AfterP2pRemove_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
std::string p2p_iface_name = createIface(IfaceType::P2P);
ASSERT_FALSE(p2p_iface_name.empty());
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
// After removing P2P iface, NAN iface creation should succeed.
removeIface(IfaceType::P2P, p2p_iface_name);
ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_AfterNanRemove_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
std::string nan_iface_name = createIface(IfaceType::NAN_IFACE);
ASSERT_FALSE(nan_iface_name.empty());
ASSERT_TRUE(createIface(IfaceType::P2P).empty());
// After removing NAN iface, P2P iface creation should succeed.
removeIface(IfaceType::NAN_IFACE, nan_iface_name);
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_FALSE(createIface(IfaceType::AP).empty());
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_FALSE(createIface(IfaceType::AP).empty());
ASSERT_TRUE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
std::string p2p_iface_name = createIface(IfaceType::P2P);
ASSERT_FALSE(p2p_iface_name.empty());
ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
// After removing P2P iface, NAN iface creation should succeed.
removeIface(IfaceType::P2P, p2p_iface_name);
ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
std::string nan_iface_name = createIface(IfaceType::NAN_IFACE);
ASSERT_FALSE(nan_iface_name.empty());
ASSERT_TRUE(createIface(IfaceType::P2P).empty());
// After removing NAN iface, P2P iface creation should succeed.
removeIface(IfaceType::NAN_IFACE, nan_iface_name);
ASSERT_FALSE(createIface(IfaceType::P2P).empty());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_EnsureDifferentIfaceNames) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
std::string sta_iface_name = createIface(IfaceType::STA);
std::string ap_iface_name = createIface(IfaceType::AP);
ASSERT_FALSE(sta_iface_name.empty());
ASSERT_FALSE(ap_iface_name.empty());
ASSERT_NE(sta_iface_name, ap_iface_name);
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_TRUE(createRttController());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_TRUE(createRttController());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::AP).empty());
ASSERT_TRUE(createRttController());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
.WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
.WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveNanOnStaRemove) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
// Create NAN iface
ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "wlan0");
// We should have 1 nan iface.
std::vector<std::string> iface_names;
ASSERT_TRUE(chip_->getNanIfaceNames(&iface_names).isOk());
ASSERT_EQ(iface_names.size(), 1u);
ASSERT_EQ(iface_names[0], "wlan0");
// Retrieve the nan iface object.
std::shared_ptr<IWifiNanIface> nan_iface;
ASSERT_TRUE(chip_->getNanIface("wlan0", &nan_iface).isOk());
ASSERT_NE(nan_iface.get(), nullptr);
// Remove the STA iface. We should have 0 nan ifaces now.
removeIface(IfaceType::STA, "wlan0");
ASSERT_TRUE(chip_->getNanIfaceNames(&iface_names).isOk());
ASSERT_EQ(iface_names.size(), 0u);
// Any operation on the nan iface object should now return an error.
std::string name;
auto status = nan_iface->getName(&name);
ASSERT_EQ(status.getServiceSpecificError(),
static_cast<int32_t>(WifiStatusCode::ERROR_WIFI_IFACE_INVALID));
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveRttControllerOnStaRemove) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
// Create RTT controller
std::shared_ptr<IWifiRttController> rtt_controller;
ASSERT_TRUE(chip_->createRttController(nullptr, &rtt_controller).isOk());
// Remove the STA iface.
removeIface(IfaceType::STA, "wlan0");
// Any operation on the rtt controller object should now return an error.
std::shared_ptr<IWifiStaIface> bound_iface;
auto status = rtt_controller->getBoundIface(&bound_iface);
ASSERT_EQ(status.getServiceSpecificError(),
static_cast<int32_t>(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID));
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) {
property_set("wifi.aware.interface", nullptr);
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "wlan0");
removeIface(IfaceType::NAN_IFACE, "wlan0");
EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0);
}
TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) {
property_set("wifi.aware.interface", "aware0");
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
EXPECT_CALL(*iface_util_, ifNameToIndex("aware0")).WillOnce(testing::Return(4));
EXPECT_CALL(*iface_util_, setUpState("aware0", true)).WillOnce(testing::Return(true));
ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "aware0");
EXPECT_CALL(*iface_util_, setUpState("aware0", false)).WillOnce(testing::Return(true));
removeIface(IfaceType::NAN_IFACE, "aware0");
}
////////// V1 Iface Combinations when AP creation is disabled //////////
class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
public:
void SetUp() override {
setupV1_AwareDisabledApIfaceCombination();
WifiChipTest::SetUp();
}
};
TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_TRUE(createIface(IfaceType::AP).empty());
}
////////// V2 Iface Combinations when AP creation is disabled //////////
class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
public:
void SetUp() override {
setupV2_AwareDisabledApIfaceCombination();
WifiChipTest::SetUp();
}
};
TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest, CreateSta_ShouldSucceed) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_TRUE(createIface(IfaceType::AP).empty());
}
////////// Hypothetical Iface Combination with multiple ifaces //////////
class WifiChip_MultiIfaceTest : public WifiChipTest {
public:
void SetUp() override {
setup_MultiIfaceCombination();
WifiChipTest::SetUp();
}
};
TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_FALSE(createIface(IfaceType::STA).empty());
ASSERT_TRUE(createIface(IfaceType::STA).empty());
}
TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
property_set("wifi.interface.0", "");
property_set("wifi.interface.1", "");
property_set("wifi.interface.2", "");
property_set("wifi.interface", "");
property_set("wifi.concurrent.interface", "");
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
}
TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
property_set("wifi.interface.0", "test0");
property_set("wifi.interface.1", "test1");
property_set("wifi.interface.2", "test2");
property_set("wifi.interface", "bad0");
property_set("wifi.concurrent.interface", "bad1");
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "bad0");
ASSERT_EQ(createIface(IfaceType::STA), "bad1");
ASSERT_EQ(createIface(IfaceType::STA), "test2");
}
TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
property_set("wifi.interface.0", "");
property_set("wifi.interface.1", "");
property_set("wifi.interface.2", "");
property_set("wifi.interface", "testA0");
property_set("wifi.concurrent.interface", "testA1");
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
ASSERT_EQ(createIface(IfaceType::STA), "testA0");
ASSERT_EQ(createIface(IfaceType::STA), "testA1");
ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
}
TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
// WifiChip_MultiIfaceTest iface combo: STAx3 + APx1
// When the HAL support dual STAs, AP should start with idx 2.
findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
// First AP will be slotted to wlan1.
ASSERT_EQ(createIface(IfaceType::AP), "wlan2");
// First STA will be slotted to wlan0.
ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
// All further STA will be slotted to the remaining free indices.
ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,94 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <gmock/gmock.h>
#include "wifi_iface_util.h"
#include "mock_interface_tool.h"
#include "mock_wifi_legacy_hal.h"
using testing::NiceMock;
using testing::Test;
namespace {
constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
constexpr char kIfaceName[] = "test-wlan0";
bool isValidUnicastLocallyAssignedMacAddress(const std::array<uint8_t, 6>& mac_address) {
uint8_t first_byte = mac_address[0];
return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
}
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace iface_util {
class WifiIfaceUtilTest : public Test {
protected:
std::shared_ptr<NiceMock<::android::wifi_system::MockInterfaceTool>> iface_tool_{
new NiceMock<::android::wifi_system::MockInterfaceTool>};
legacy_hal::wifi_hal_fn fake_func_table_;
std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_, legacy_hal_);
};
TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
auto mac_address = iface_util_->getOrCreateRandomMacAddress();
ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
// All further calls should return the same MAC address.
ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
}
TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
std::array<uint8_t, 6> mac_address = {};
std::copy(std::begin(kMacAddress), std::end(kMacAddress), std::begin(mac_address));
EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
.WillRepeatedly(testing::Return(true));
EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
.WillRepeatedly(testing::Return(true));
// Register for iface state toggle events.
bool callback_invoked = false;
iface_util::IfaceEventHandlers event_handlers = {};
event_handlers.on_state_toggle_off_on =
[&callback_invoked](const std::string& /* iface_name */) { callback_invoked = true; };
iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
// Invoke setMacAddress and ensure that the cb is invoked.
ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
ASSERT_TRUE(callback_invoked);
// Unregister for iface state toggle events.
callback_invoked = false;
iface_util_->unregisterIfaceEventHandlers(kIfaceName);
// Invoke setMacAddress and ensure that the cb is not invoked.
ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
ASSERT_FALSE(callback_invoked);
}
} // namespace iface_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,168 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <cutils/properties.h>
#include <gmock/gmock.h>
#include "wifi_nan_iface.h"
#include "mock_interface_tool.h"
#include "mock_wifi_feature_flags.h"
#include "mock_wifi_iface_util.h"
#include "mock_wifi_legacy_hal.h"
using testing::NiceMock;
using testing::Return;
using testing::Test;
namespace {
constexpr char kIfaceName[] = "mockWlan0";
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
bool CaptureIfaceEventHandlers(const std::string& /* iface_name*/,
iface_util::IfaceEventHandlers in_iface_event_handlers,
iface_util::IfaceEventHandlers* out_iface_event_handlers) {
*out_iface_event_handlers = in_iface_event_handlers;
return true;
}
class MockNanIface : public WifiNanIface {
public:
MockNanIface(const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: WifiNanIface(ifname, is_dedicated_iface, legacy_hal, iface_util) {}
static std::shared_ptr<MockNanIface> createMock(
const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util) {
std::shared_ptr<MockNanIface> ptr = ndk::SharedRefBase::make<MockNanIface>(
ifname, is_dedicated_iface, legacy_hal, iface_util);
std::weak_ptr<MockNanIface> weak_ptr_this(ptr);
ptr->setWeakPtr(weak_ptr_this);
ptr->registerCallbackHandlers();
return ptr;
}
// Override getEventCallbacks() so that we can return a mocked callback object.
std::set<std::shared_ptr<IWifiNanIfaceEventCallback>> getEventCallbacks() override {
return {callback_};
}
void setMockCallback(std::shared_ptr<IWifiNanIfaceEventCallback> cb) { callback_ = cb; }
private:
std::shared_ptr<IWifiNanIfaceEventCallback> callback_;
};
class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback {
public:
ndk::SpAIBinder asBinder() override { return ::ndk::SpAIBinder{}; }
bool isRemote() override { return false; }
::ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) override {
*_aidl_return = 1;
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus getInterfaceHash(std::string* _aidl_return) override {
*_aidl_return = "some_hash";
return ndk::ScopedAStatus::ok();
}
MOCK_METHOD3(notifyCapabilitiesResponse,
ndk::ScopedAStatus(char16_t, const NanStatus&, const NanCapabilities&));
MOCK_METHOD2(notifyEnableResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD2(notifyConfigResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD2(notifyDisableResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD3(notifyStartPublishResponse,
ndk::ScopedAStatus(char16_t, const NanStatus&, int8_t));
MOCK_METHOD2(notifyStopPublishResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD3(notifyStartSubscribeResponse,
ndk::ScopedAStatus(char16_t, const NanStatus&, int8_t));
MOCK_METHOD2(notifyStopSubscribeResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD2(notifyTransmitFollowupResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD2(notifyCreateDataInterfaceResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD2(notifyDeleteDataInterfaceResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD3(notifyInitiateDataPathResponse,
ndk::ScopedAStatus(char16_t, const NanStatus&, int32_t));
MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD2(notifyTerminateDataPathResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD1(eventClusterEvent, ndk::ScopedAStatus(const NanClusterEventInd&));
MOCK_METHOD1(eventDisabled, ndk::ScopedAStatus(const NanStatus&));
MOCK_METHOD2(eventPublishTerminated, ndk::ScopedAStatus(int8_t, const NanStatus&));
MOCK_METHOD2(eventSubscribeTerminated, ndk::ScopedAStatus(int8_t, const NanStatus&));
MOCK_METHOD1(eventMatch, ndk::ScopedAStatus(const NanMatchInd&));
MOCK_METHOD2(eventMatchExpired, ndk::ScopedAStatus(int8_t, int32_t));
MOCK_METHOD1(eventFollowupReceived, ndk::ScopedAStatus(const NanFollowupReceivedInd&));
MOCK_METHOD2(eventTransmitFollowup, ndk::ScopedAStatus(char16_t, const NanStatus&));
MOCK_METHOD1(eventDataPathRequest, ndk::ScopedAStatus(const NanDataPathRequestInd&));
MOCK_METHOD1(eventDataPathConfirm, ndk::ScopedAStatus(const NanDataPathConfirmInd&));
MOCK_METHOD1(eventDataPathTerminated, ndk::ScopedAStatus(int32_t));
MOCK_METHOD1(eventDataPathScheduleUpdate,
ndk::ScopedAStatus(const NanDataPathScheduleUpdateInd&));
};
class WifiNanIfaceTest : public Test {
protected:
legacy_hal::wifi_hal_fn fake_func_table_;
std::shared_ptr<NiceMock<::android::wifi_system::MockInterfaceTool>> iface_tool_{
new NiceMock<::android::wifi_system::MockInterfaceTool>};
std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
};
TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
// Ensure that event handlers are registered during nan iface creation.
iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
EXPECT_CALL(*legacy_hal_, nanRegisterCallbackHandlers(testing::_, testing::_))
.WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
EXPECT_CALL(*iface_util_, registerIfaceEventHandlers(testing::_, testing::_))
.WillOnce(testing::Invoke(bind(CaptureIfaceEventHandlers, std::placeholders::_1,
std::placeholders::_2, &captured_iface_event_handlers)));
// Create nan iface and register a callback.
// Note: Since we can't register a callback directly (gTest fails on
// AIBinder_linkToDeath), simulate the registration by overriding
// getEventCallbacks() to return our mock callback object.
std::shared_ptr<MockNanIface> mock_nan_iface =
MockNanIface::createMock(kIfaceName, false, legacy_hal_, iface_util_);
std::shared_ptr<MockNanIfaceEventCallback> mock_event_callback =
ndk::SharedRefBase::make<MockNanIfaceEventCallback>();
mock_nan_iface->setMockCallback(mock_event_callback);
// Ensure that the eventDisabled() function in the mock callback will be invoked.
NanStatus expected_nan_status = {NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status)).Times(1);
// Trigger the iface state toggle callback.
captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

284
wifi/aidl/default/wifi.cpp Normal file
View File

@@ -0,0 +1,284 @@
/*
* 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.h"
#include <android-base/logging.h>
#include "aidl_return_util.h"
#include "wifi_status_util.h"
namespace {
// Starting Chip ID, will be assigned to primary chip
static constexpr int32_t kPrimaryChipId = 0;
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using aidl_return_util::validateAndCall;
using aidl_return_util::validateAndCallWithLock;
Wifi::Wifi(const std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
: iface_tool_(iface_tool),
legacy_hal_factory_(legacy_hal_factory),
mode_controller_(mode_controller),
feature_flags_(feature_flags),
run_state_(RunState::STOPPED) {}
bool Wifi::isValid() {
// This object is always valid.
return true;
}
ndk::ScopedAStatus Wifi::registerEventCallback(
const std::shared_ptr<IWifiEventCallback>& in_callback) {
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
&Wifi::registerEventCallbackInternal, in_callback);
}
ndk::ScopedAStatus Wifi::isStarted(bool* _aidl_return) {
*_aidl_return = (run_state_ != RunState::STOPPED);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Wifi::start() {
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal);
}
ndk::ScopedAStatus Wifi::stop() {
return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::stopInternal);
}
ndk::ScopedAStatus Wifi::getChipIds(std::vector<int32_t>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipIdsInternal,
_aidl_return);
}
ndk::ScopedAStatus Wifi::getChip(int32_t in_chipId, std::shared_ptr<IWifiChip>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipInternal,
_aidl_return, in_chipId);
}
binder_status_t Wifi::dump(int fd, const char** args, uint32_t numArgs) {
LOG(INFO) << "-----------Debug was called----------------";
if (chips_.size() == 0) {
LOG(INFO) << "No chips to display.";
return STATUS_OK;
}
for (std::shared_ptr<WifiChip> chip : chips_) {
if (!chip.get()) continue;
chip->dump(fd, args, numArgs);
}
return STATUS_OK;
}
ndk::ScopedAStatus Wifi::registerEventCallbackInternal(
const std::shared_ptr<IWifiEventCallback>& event_callback) {
if (!event_cb_handler_.addCallback(event_callback)) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Wifi::startInternal() {
if (run_state_ == RunState::STARTED) {
return ndk::ScopedAStatus::ok();
} else if (run_state_ == RunState::STOPPING) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
}
ndk::ScopedAStatus wifi_status = initializeModeControllerAndLegacyHal();
if (wifi_status.isOk()) {
// Register the callback for subsystem restart
const auto& on_subsystem_restart_callback = [this](const std::string& error) {
ndk::ScopedAStatus wifi_status = createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
LOG(INFO) << "Attempting to invoke onSubsystemRestart "
"callback";
WifiStatusCode errorCode =
static_cast<WifiStatusCode>(wifi_status.getServiceSpecificError());
if (!callback->onSubsystemRestart(errorCode).isOk()) {
LOG(ERROR) << "Failed to invoke onSubsystemRestart callback";
} else {
LOG(INFO) << "Succeeded to invoke onSubsystemRestart "
"callback";
}
}
};
// Create the chip instance once the HAL is started.
int32_t chipId = kPrimaryChipId;
for (auto& hal : legacy_hals_) {
chips_.push_back(
WifiChip::create(chipId, chipId == kPrimaryChipId, hal, mode_controller_,
std::make_shared<iface_util::WifiIfaceUtil>(iface_tool_, hal),
feature_flags_, on_subsystem_restart_callback));
chipId++;
}
run_state_ = RunState::STARTED;
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onStart().isOk()) {
LOG(ERROR) << "Failed to invoke onStart callback";
};
}
LOG(INFO) << "Wifi HAL started";
} else {
for (const auto& callback : event_cb_handler_.getCallbacks()) {
WifiStatusCode errorCode =
static_cast<WifiStatusCode>(wifi_status.getServiceSpecificError());
if (!callback->onFailure(errorCode).isOk()) {
LOG(ERROR) << "Failed to invoke onFailure callback";
}
}
LOG(ERROR) << "Wifi HAL start failed";
// Clear the event callback objects since the HAL start failed.
event_cb_handler_.invalidate();
}
return wifi_status;
}
ndk::ScopedAStatus Wifi::stopInternal(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
if (run_state_ == RunState::STOPPED) {
return ndk::ScopedAStatus::ok();
} else if (run_state_ == RunState::STOPPING) {
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
}
// Clear the chip object and its child objects since the HAL is now
// stopped.
for (auto& chip : chips_) {
if (chip.get()) {
chip->invalidate();
chip.reset();
}
}
chips_.clear();
ndk::ScopedAStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
if (wifi_status.isOk()) {
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onStop().isOk()) {
LOG(ERROR) << "Failed to invoke onStop callback";
};
}
LOG(INFO) << "Wifi HAL stopped";
} else {
for (const auto& callback : event_cb_handler_.getCallbacks()) {
WifiStatusCode errorCode =
static_cast<WifiStatusCode>(wifi_status.getServiceSpecificError());
if (!callback->onFailure(errorCode).isOk()) {
LOG(ERROR) << "Failed to invoke onFailure callback";
}
}
LOG(ERROR) << "Wifi HAL stop failed";
}
// Clear the event callback objects since the HAL is now stopped.
event_cb_handler_.invalidate();
return wifi_status;
}
std::pair<std::vector<int32_t>, ndk::ScopedAStatus> Wifi::getChipIdsInternal() {
std::vector<int32_t> chip_ids;
for (auto& chip : chips_) {
int32_t chip_id = getChipIdFromWifiChip(chip);
if (chip_id != INT32_MAX) chip_ids.emplace_back(chip_id);
}
return {std::move(chip_ids), ndk::ScopedAStatus::ok()};
}
std::pair<std::shared_ptr<IWifiChip>, ndk::ScopedAStatus> Wifi::getChipInternal(int32_t chip_id) {
for (auto& chip : chips_) {
int32_t cand_id = getChipIdFromWifiChip(chip);
if ((cand_id != INT32_MAX) && (cand_id == chip_id)) return {chip, ndk::ScopedAStatus::ok()};
}
return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
}
ndk::ScopedAStatus Wifi::initializeModeControllerAndLegacyHal() {
if (!mode_controller_->initialize()) {
LOG(ERROR) << "Failed to initialize firmware mode controller";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
legacy_hals_ = legacy_hal_factory_->getHals();
if (legacy_hals_.empty()) return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
int index = 0; // for failure log
for (auto& hal : legacy_hals_) {
legacy_hal::wifi_error legacy_status = hal->initialize();
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
// Currently WifiLegacyHal::initialize does not allocate extra mem,
// only initializes the function table. If this changes, need to
// implement WifiLegacyHal::deinitialize and deinitalize the
// HALs already initialized
LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
<< " error: " << legacyErrorToString(legacy_status);
return createWifiStatusFromLegacyError(legacy_status);
}
index++;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Wifi::stopLegacyHalAndDeinitializeModeController(
/* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
int index = 0;
run_state_ = RunState::STOPPING;
for (auto& hal : legacy_hals_) {
legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
if (tmp != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to stop legacy HAL index: " << index
<< " error: " << legacyErrorToString(legacy_status);
legacy_status = tmp;
}
index++;
}
run_state_ = RunState::STOPPED;
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "One or more legacy HALs failed to stop";
return createWifiStatusFromLegacyError(legacy_status);
}
if (!mode_controller_->deinitialize()) {
LOG(ERROR) << "Failed to deinitialize firmware mode controller";
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
int32_t Wifi::getChipIdFromWifiChip(std::shared_ptr<WifiChip>& chip) {
int32_t chip_id = INT32_MAX;
if (chip.get()) {
ndk::ScopedAStatus status = chip->getId(&chip_id);
if (!status.isOk()) {
// Reset value if operation failed.
chip_id = INT32_MAX;
}
}
return chip_id;
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

96
wifi/aidl/default/wifi.h Normal file
View File

@@ -0,0 +1,96 @@
/*
* 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.
*/
#ifndef WIFI_H_
#define WIFI_H_
#include <aidl/android/hardware/wifi/BnWifi.h>
#include <android-base/macros.h>
#include <utils/Looper.h>
#include <functional>
#include "aidl_callback_util.h"
#include "wifi_chip.h"
#include "wifi_feature_flags.h"
#include "wifi_legacy_hal.h"
#include "wifi_legacy_hal_factory.h"
#include "wifi_mode_controller.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* Root AIDL interface object used to control the Wifi HAL.
*/
class Wifi : public BnWifi {
public:
Wifi(const std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
bool isValid();
// AIDL methods exposed.
ndk::ScopedAStatus registerEventCallback(
const std::shared_ptr<IWifiEventCallback>& in_callback) override;
ndk::ScopedAStatus isStarted(bool* _aidl_return) override;
ndk::ScopedAStatus start() override;
ndk::ScopedAStatus stop() override;
ndk::ScopedAStatus getChipIds(std::vector<int32_t>* _aidl_return) override;
ndk::ScopedAStatus getChip(int32_t in_chipId,
std::shared_ptr<IWifiChip>* _aidl_return) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
enum class RunState { STOPPED, STARTED, STOPPING };
// Corresponding worker functions for the AIDL methods.
ndk::ScopedAStatus registerEventCallbackInternal(
const std::shared_ptr<IWifiEventCallback>& event_callback __unused);
ndk::ScopedAStatus startInternal();
ndk::ScopedAStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
std::pair<std::vector<int32_t>, ndk::ScopedAStatus> getChipIdsInternal();
std::pair<std::shared_ptr<IWifiChip>, ndk::ScopedAStatus> getChipInternal(int32_t chip_id);
ndk::ScopedAStatus initializeModeControllerAndLegacyHal();
ndk::ScopedAStatus stopLegacyHalAndDeinitializeModeController(
std::unique_lock<std::recursive_mutex>* lock);
int32_t getChipIdFromWifiChip(std::shared_ptr<WifiChip>& chip);
// Instance is created in this root level |IWifi| AIDL interface object
// and shared with all the child AIDL interface objects.
std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
RunState run_state_;
std::vector<std::shared_ptr<WifiChip>> chips_;
aidl_callback_util::AidlCallbackHandler<IWifiEventCallback> event_cb_handler_;
DISALLOW_COPY_AND_ASSIGN(Wifi);
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_H_

View File

@@ -0,0 +1,190 @@
/*
* 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_ap_iface.h"
#include <android-base/logging.h>
#include "aidl_return_util.h"
#include "aidl_struct_util.h"
#include "wifi_status_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using aidl_return_util::validateAndCall;
WifiApIface::WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: ifname_(ifname),
instances_(instances),
legacy_hal_(legacy_hal),
iface_util_(iface_util),
is_valid_(true) {}
void WifiApIface::invalidate() {
legacy_hal_.reset();
is_valid_ = false;
}
bool WifiApIface::isValid() {
return is_valid_;
}
std::string WifiApIface::getName() {
return ifname_;
}
void WifiApIface::removeInstance(std::string instance) {
instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end());
}
ndk::ScopedAStatus WifiApIface::getName(std::string* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::getNameInternal, _aidl_return);
}
ndk::ScopedAStatus WifiApIface::setCountryCode(const std::array<uint8_t, 2>& in_code) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::setCountryCodeInternal, in_code);
}
ndk::ScopedAStatus WifiApIface::getValidFrequenciesForBand(WifiBand in_band,
std::vector<int32_t>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::getValidFrequenciesForBandInternal, _aidl_return, in_band);
}
ndk::ScopedAStatus WifiApIface::setMacAddress(const std::array<uint8_t, 6>& in_mac) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::setMacAddressInternal, in_mac);
}
ndk::ScopedAStatus WifiApIface::getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::getFactoryMacAddressInternal, _aidl_return,
instances_.size() > 0 ? instances_[0] : ifname_);
}
ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddress() {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::resetToFactoryMacAddressInternal);
}
ndk::ScopedAStatus WifiApIface::getBridgedInstances(std::vector<std::string>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiApIface::getBridgedInstancesInternal, _aidl_return);
}
std::pair<std::string, ndk::ScopedAStatus> WifiApIface::getNameInternal() {
return {ifname_, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiApIface::setCountryCodeInternal(const std::array<uint8_t, 2>& code) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
instances_.size() > 0 ? instances_[0] : ifname_, code);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<std::vector<int32_t>, ndk::ScopedAStatus> WifiApIface::getValidFrequenciesForBandInternal(
WifiBand band) {
static_assert(sizeof(WifiChannelWidthInMhz) == sizeof(int32_t), "Size mismatch");
legacy_hal::wifi_error legacy_status;
std::vector<uint32_t> valid_frequencies;
std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
instances_.size() > 0 ? instances_[0] : ifname_,
aidl_struct_util::convertAidlWifiBandToLegacy(band));
return {std::vector<int32_t>(valid_frequencies.begin(), valid_frequencies.end()),
createWifiStatusFromLegacyError(legacy_status)};
}
ndk::ScopedAStatus WifiApIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
// Support random MAC up to 2 interfaces
if (instances_.size() == 2) {
int rbyte = 1;
for (auto const& intf : instances_) {
std::array<uint8_t, 6> rmac = mac;
// reverse the bits to avoid collision
rmac[rbyte] = 0xff - rmac[rbyte];
if (!iface_util_.lock()->setMacAddress(intf, rmac)) {
LOG(INFO) << "Failed to set random mac address on " << intf;
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
rbyte++;
}
}
// It also needs to set mac address for bridged interface, otherwise the mac
// address of bridged interface will be changed after one of instance
// down.
if (!iface_util_.lock()->setMacAddress(ifname_, mac)) {
LOG(ERROR) << "Fail to config MAC for interface " << ifname_;
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> WifiApIface::getFactoryMacAddressInternal(
const std::string& ifaceName) {
std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifaceName);
if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
return {mac, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {mac, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddressInternal() {
std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getMacResult;
if (instances_.size() == 2) {
for (auto const& intf : instances_) {
getMacResult = getFactoryMacAddressInternal(intf);
LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
if (!getMacResult.second.isOk() ||
!iface_util_.lock()->setMacAddress(intf, getMacResult.first)) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
}
// We need to set mac address for bridged interface, otherwise the mac
// address of the bridged interface will be changed after one of the
// instances goes down. Thus we are generating a random MAC address for
// the bridged interface even if we got the request to reset the Factory
// MAC. This is because the bridged interface is an internal interface
// for the operation of bpf and other networking operations.
if (!iface_util_.lock()->setMacAddress(ifname_,
iface_util_.lock()->createRandomMacAddress())) {
LOG(ERROR) << "Fail to config MAC for bridged interface " << ifname_;
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
} else {
getMacResult = getFactoryMacAddressInternal(ifname_);
LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_;
if (!getMacResult.second.isOk() ||
!iface_util_.lock()->setMacAddress(ifname_, getMacResult.first)) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
}
return ndk::ScopedAStatus::ok();
}
std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiApIface::getBridgedInstancesInternal() {
return {instances_, ndk::ScopedAStatus::ok()};
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,81 @@
/*
* 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.
*/
#ifndef WIFI_AP_IFACE_H_
#define WIFI_AP_IFACE_H_
#include <aidl/android/hardware/wifi/BnWifiApIface.h>
#include <android-base/macros.h>
#include "wifi_iface_util.h"
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* AIDL interface object used to control an AP Iface instance.
*/
class WifiApIface : public BnWifiApIface {
public:
WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
std::string getName();
void removeInstance(std::string instance);
// AIDL methods exposed.
ndk::ScopedAStatus getName(std::string* _aidl_return) override;
ndk::ScopedAStatus setCountryCode(const std::array<uint8_t, 2>& in_code) override;
ndk::ScopedAStatus getValidFrequenciesForBand(WifiBand in_band,
std::vector<int32_t>* _aidl_return) override;
ndk::ScopedAStatus setMacAddress(const std::array<uint8_t, 6>& in_mac) override;
ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
ndk::ScopedAStatus resetToFactoryMacAddress() override;
ndk::ScopedAStatus getBridgedInstances(std::vector<std::string>* _aidl_return) override;
private:
// Corresponding worker functions for the AIDL methods.
std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
ndk::ScopedAStatus setCountryCodeInternal(const std::array<uint8_t, 2>& code);
std::pair<std::vector<int32_t>, ndk::ScopedAStatus> getValidFrequenciesForBandInternal(
WifiBand band);
ndk::ScopedAStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getFactoryMacAddressInternal(
const std::string& ifaceName);
ndk::ScopedAStatus resetToFactoryMacAddressInternal();
std::pair<std::vector<std::string>, ndk::ScopedAStatus> getBridgedInstancesInternal();
std::string ifname_;
std::vector<std::string> instances_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiApIface);
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_AP_IFACE_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,287 @@
/*
* 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.
*/
#ifndef WIFI_CHIP_H_
#define WIFI_CHIP_H_
#include <aidl/android/hardware/wifi/BnWifiChip.h>
#include <aidl/android/hardware/wifi/IWifiRttController.h>
#include <android-base/macros.h>
#include <list>
#include <map>
#include <mutex>
#include "aidl_callback_util.h"
#include "ringbuffer.h"
#include "wifi_ap_iface.h"
#include "wifi_feature_flags.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"
#include "wifi_sta_iface.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* AIDL interface object used to control a Wifi HAL chip instance.
* Since there is only a single chip instance used today, there is no
* identifying handle information stored here.
*/
class WifiChip : public BnWifiChip {
public:
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&)>& subsystemCallbackHandler);
// Factory method - use instead of default constructor.
static std::shared_ptr<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&)>& subsystemCallbackHandler);
// AIDL does not provide a built-in mechanism to let the server invalidate
// an AIDL interface object after creation. If any client process holds onto
// a reference to the object in their context, any method calls on that
// reference will continue to be directed to the server.
//
// However Wifi HAL needs to control the lifetime of these objects. So, add
// a public |invalidate| method to |WifiChip| and its child objects. This
// will be used to mark an object invalid when either:
// a) Wifi HAL is stopped, or
// b) Wifi Chip is reconfigured.
//
// All AIDL method implementations should check if the object is still
// marked valid before processing them.
void invalidate();
bool isValid();
std::set<std::shared_ptr<IWifiChipEventCallback>> getEventCallbacks();
// AIDL methods exposed.
ndk::ScopedAStatus getId(int32_t* _aidl_return) override;
ndk::ScopedAStatus registerEventCallback(
const std::shared_ptr<IWifiChipEventCallback>& in_callback) override;
ndk::ScopedAStatus getCapabilities(IWifiChip::ChipCapabilityMask* _aidl_return) override;
ndk::ScopedAStatus getAvailableModes(std::vector<IWifiChip::ChipMode>* _aidl_return) override;
ndk::ScopedAStatus configureChip(int32_t in_modeId) override;
ndk::ScopedAStatus getMode(int32_t* _aidl_return) override;
ndk::ScopedAStatus requestChipDebugInfo(IWifiChip::ChipDebugInfo* _aidl_return) override;
ndk::ScopedAStatus requestDriverDebugDump(std::vector<uint8_t>* _aidl_return) override;
ndk::ScopedAStatus requestFirmwareDebugDump(std::vector<uint8_t>* _aidl_return) override;
ndk::ScopedAStatus createApIface(std::shared_ptr<IWifiApIface>* _aidl_return) override;
ndk::ScopedAStatus createBridgedApIface(std::shared_ptr<IWifiApIface>* _aidl_return) override;
ndk::ScopedAStatus getApIfaceNames(std::vector<std::string>* _aidl_return) override;
ndk::ScopedAStatus getApIface(const std::string& in_ifname,
std::shared_ptr<IWifiApIface>* _aidl_return) override;
ndk::ScopedAStatus removeApIface(const std::string& in_ifname) override;
ndk::ScopedAStatus removeIfaceInstanceFromBridgedApIface(
const std::string& in_brIfaceName, const std::string& in_ifaceInstanceName) override;
ndk::ScopedAStatus createNanIface(std::shared_ptr<IWifiNanIface>* _aidl_return) override;
ndk::ScopedAStatus getNanIfaceNames(std::vector<std::string>* _aidl_return) override;
ndk::ScopedAStatus getNanIface(const std::string& in_ifname,
std::shared_ptr<IWifiNanIface>* _aidl_return) override;
ndk::ScopedAStatus removeNanIface(const std::string& in_ifname) override;
ndk::ScopedAStatus createP2pIface(std::shared_ptr<IWifiP2pIface>* _aidl_return) override;
ndk::ScopedAStatus getP2pIfaceNames(std::vector<std::string>* _aidl_return) override;
ndk::ScopedAStatus getP2pIface(const std::string& in_ifname,
std::shared_ptr<IWifiP2pIface>* _aidl_return) override;
ndk::ScopedAStatus removeP2pIface(const std::string& in_ifname) override;
ndk::ScopedAStatus createStaIface(std::shared_ptr<IWifiStaIface>* _aidl_return) override;
ndk::ScopedAStatus getStaIfaceNames(std::vector<std::string>* _aidl_return) override;
ndk::ScopedAStatus getStaIface(const std::string& in_ifname,
std::shared_ptr<IWifiStaIface>* _aidl_return) override;
ndk::ScopedAStatus removeStaIface(const std::string& in_ifname) override;
ndk::ScopedAStatus createRttController(
const std::shared_ptr<IWifiStaIface>& in_boundIface,
std::shared_ptr<IWifiRttController>* _aidl_return) override;
ndk::ScopedAStatus getDebugRingBuffersStatus(
std::vector<WifiDebugRingBufferStatus>* _aidl_return) override;
ndk::ScopedAStatus startLoggingToDebugRingBuffer(
const std::string& in_ringName, WifiDebugRingBufferVerboseLevel in_verboseLevel,
int32_t in_maxIntervalInSec, int32_t in_minDataSizeInBytes) override;
ndk::ScopedAStatus forceDumpToDebugRingBuffer(const std::string& in_ringName) override;
ndk::ScopedAStatus flushRingBufferToFile() override;
ndk::ScopedAStatus stopLoggingToDebugRingBuffer() override;
ndk::ScopedAStatus getDebugHostWakeReasonStats(
WifiDebugHostWakeReasonStats* _aidl_return) override;
ndk::ScopedAStatus enableDebugErrorAlerts(bool in_enable) override;
ndk::ScopedAStatus selectTxPowerScenario(IWifiChip::TxPowerScenario in_scenario) override;
ndk::ScopedAStatus resetTxPowerScenario() override;
ndk::ScopedAStatus setLatencyMode(IWifiChip::LatencyMode in_mode) override;
ndk::ScopedAStatus setMultiStaPrimaryConnection(const std::string& in_ifName) override;
ndk::ScopedAStatus setMultiStaUseCase(IWifiChip::MultiStaUseCase in_useCase) override;
ndk::ScopedAStatus setCoexUnsafeChannels(
const std::vector<IWifiChip::CoexUnsafeChannel>& in_unsafeChannels,
CoexRestriction in_restrictions) override;
ndk::ScopedAStatus setCountryCode(const std::array<uint8_t, 2>& in_code) override;
ndk::ScopedAStatus getUsableChannels(WifiBand in_band, WifiIfaceMode in_ifaceModeMask,
UsableChannelFilter in_filterMask,
std::vector<WifiUsableChannel>* _aidl_return) override;
ndk::ScopedAStatus triggerSubsystemRestart() override;
ndk::ScopedAStatus getSupportedRadioCombinationsMatrix(
WifiRadioCombinationMatrix* _aidl_return) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
void invalidateAndRemoveAllIfaces();
// When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
// invalidated & removed.
void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
// Corresponding worker functions for the AIDL methods.
std::pair<int32_t, ndk::ScopedAStatus> getIdInternal();
ndk::ScopedAStatus registerEventCallbackInternal(
const std::shared_ptr<IWifiChipEventCallback>& event_callback);
std::pair<IWifiChip::ChipCapabilityMask, ndk::ScopedAStatus> getCapabilitiesInternal();
std::pair<std::vector<IWifiChip::ChipMode>, ndk::ScopedAStatus> getAvailableModesInternal();
ndk::ScopedAStatus configureChipInternal(std::unique_lock<std::recursive_mutex>* lock,
int32_t mode_id);
std::pair<int32_t, ndk::ScopedAStatus> getModeInternal();
std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> requestChipDebugInfoInternal();
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestDriverDebugDumpInternal();
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestFirmwareDebugDumpInternal();
std::shared_ptr<WifiApIface> newWifiApIface(std::string& ifname);
ndk::ScopedAStatus createVirtualApInterface(const std::string& apVirtIf);
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApIfaceInternal();
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createBridgedApIfaceInternal();
std::pair<std::vector<std::string>, ndk::ScopedAStatus> getApIfaceNamesInternal();
std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> getApIfaceInternal(
const std::string& ifname);
ndk::ScopedAStatus removeApIfaceInternal(const std::string& ifname);
ndk::ScopedAStatus removeIfaceInstanceFromBridgedApIfaceInternal(
const std::string& brIfaceName, const std::string& ifInstanceName);
std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> createNanIfaceInternal();
std::pair<std::vector<std::string>, ndk::ScopedAStatus> getNanIfaceNamesInternal();
std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> getNanIfaceInternal(
const std::string& ifname);
ndk::ScopedAStatus removeNanIfaceInternal(const std::string& ifname);
std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> createP2pIfaceInternal();
std::pair<std::vector<std::string>, ndk::ScopedAStatus> getP2pIfaceNamesInternal();
std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> getP2pIfaceInternal(
const std::string& ifname);
ndk::ScopedAStatus removeP2pIfaceInternal(const std::string& ifname);
std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> createStaIfaceInternal();
std::pair<std::vector<std::string>, ndk::ScopedAStatus> getStaIfaceNamesInternal();
std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> getStaIfaceInternal(
const std::string& ifname);
ndk::ScopedAStatus removeStaIfaceInternal(const std::string& ifname);
std::pair<std::shared_ptr<IWifiRttController>, ndk::ScopedAStatus> createRttControllerInternal(
const std::shared_ptr<IWifiStaIface>& bound_iface);
std::pair<std::vector<WifiDebugRingBufferStatus>, ndk::ScopedAStatus>
getDebugRingBuffersStatusInternal();
ndk::ScopedAStatus startLoggingToDebugRingBufferInternal(
const std::string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
ndk::ScopedAStatus forceDumpToDebugRingBufferInternal(const std::string& ring_name);
ndk::ScopedAStatus flushRingBufferToFileInternal();
ndk::ScopedAStatus stopLoggingToDebugRingBufferInternal();
std::pair<WifiDebugHostWakeReasonStats, ndk::ScopedAStatus>
getDebugHostWakeReasonStatsInternal();
ndk::ScopedAStatus enableDebugErrorAlertsInternal(bool enable);
ndk::ScopedAStatus selectTxPowerScenarioInternal(IWifiChip::TxPowerScenario scenario);
ndk::ScopedAStatus resetTxPowerScenarioInternal();
ndk::ScopedAStatus setLatencyModeInternal(IWifiChip::LatencyMode mode);
ndk::ScopedAStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
ndk::ScopedAStatus setMultiStaUseCaseInternal(IWifiChip::MultiStaUseCase use_case);
ndk::ScopedAStatus setCoexUnsafeChannelsInternal(
std::vector<IWifiChip::CoexUnsafeChannel> unsafe_channels,
CoexRestriction restrictions);
ndk::ScopedAStatus setCountryCodeInternal(const std::array<uint8_t, 2>& in_code);
std::pair<std::vector<WifiUsableChannel>, ndk::ScopedAStatus> getUsableChannelsInternal(
WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask);
ndk::ScopedAStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
int32_t mode_id);
ndk::ScopedAStatus registerDebugRingBufferCallback();
ndk::ScopedAStatus registerRadioModeChangeCallback();
std::vector<ChipConcurrencyCombination> getCurrentModeConcurrencyCombinations();
std::map<IfaceConcurrencyType, size_t> getCurrentConcurrencyCombination();
std::vector<std::map<IfaceConcurrencyType, size_t>> expandConcurrencyCombinations(
const ChipConcurrencyCombination& combination);
bool canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(
const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
IfaceConcurrencyType requested_type);
bool canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType requested_type);
bool canExpandedConcurrencyComboSupportConcurrencyCombo(
const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
const std::map<IfaceConcurrencyType, size_t>& req_combo);
bool canCurrentModeSupportConcurrencyCombo(
const std::map<IfaceConcurrencyType, size_t>& req_combo);
bool canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type);
bool isValidModeId(int32_t mode_id);
bool isStaApConcurrencyAllowedInCurrentMode();
bool isDualStaConcurrencyAllowedInCurrentMode();
uint32_t startIdxOfApIface();
std::string getFirstActiveWlanIfaceName();
std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
std::string allocateApIfaceName();
std::vector<std::string> allocateBridgedApInstanceNames();
std::string allocateStaIfaceName();
bool writeRingbufferFilesInternal();
std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
void invalidateAndClearBridgedApAll();
void invalidateAndClearBridgedAp(const std::string& br_name);
bool findUsingNameFromBridgedApInstances(const std::string& name);
ndk::ScopedAStatus triggerSubsystemRestartInternal();
std::pair<WifiRadioCombinationMatrix, ndk::ScopedAStatus>
getSupportedRadioCombinationsMatrixInternal();
void setWeakPtr(std::weak_ptr<WifiChip> ptr);
int32_t chip_id_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
std::vector<std::shared_ptr<WifiApIface>> ap_ifaces_;
std::vector<std::shared_ptr<WifiNanIface>> nan_ifaces_;
std::vector<std::shared_ptr<WifiP2pIface>> p2p_ifaces_;
std::vector<std::shared_ptr<WifiStaIface>> sta_ifaces_;
std::vector<std::shared_ptr<WifiRttController>> rtt_controllers_;
std::map<std::string, Ringbuffer> ringbuffer_map_;
bool is_valid_;
// Members pertaining to chip configuration.
int32_t current_mode_id_;
std::mutex lock_t;
std::vector<IWifiChip::ChipMode> modes_;
// The legacy ring buffer callback API has only a global callback
// registration mechanism. Use this to check if we have already
// registered a callback.
bool debug_ring_buffer_cb_registered_;
aidl_callback_util::AidlCallbackHandler<IWifiChipEventCallback> event_cb_handler_;
std::weak_ptr<WifiChip> weak_ptr_this_;
const std::function<void(const std::string&)> subsystemCallbackHandler_;
std::map<std::string, std::vector<std::string>> br_ifaces_ap_instances_;
DISALLOW_COPY_AND_ASSIGN(WifiChip);
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_CHIP_H_

View File

@@ -0,0 +1,228 @@
/*
* 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 <string>
#include <android-base/logging.h>
#include <cutils/properties.h>
#include "wifi_feature_flags.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace feature_flags {
/* The chip may either have a single mode supporting any number of combinations,
* or a fixed dual-mode (so it involves firmware loading to switch between
* modes) setting. If there is a need to support more modes, it needs to be
* implemented manually in WiFi HAL (see changeFirmwareMode in
* WifiChip::handleChipConfiguration).
*
* Supported combinations are defined in device's makefile, for example:
* WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
* WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
* What this means:
* Interface concurrency combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
* operations.
* Interface concurrency combination 2: 1 STA and 2 AP concurrent iface operations.
*
* For backward compatibility, the following makefile flags can be used to
* generate combinations list:
* - WIFI_HIDL_FEATURE_DUAL_INTERFACE
* - WIFI_HIDL_FEATURE_DISABLE_AP
* - WIFI_HIDL_FEATURE_AWARE
* However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
* With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
* two concurrency combinations:
* Interface Concurrency Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
* concurrent iface operations.
* Interface Concurrency Combination 2: Will support 1 STA and 1 AP concurrent
* iface operations.
*
* The only dual-mode configuration supported is for alternating STA and AP
* mode, that may involve firmware reloading. In such case, there are 2 separate
* modes of operation with 1 concurrency 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.
*
* If Aware is enabled, the concurrency combination will be modified to support either
* P2P or NAN in place of just P2P.
*/
// clang-format off
#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
constexpr int kMainModeId = chip_mode_ids::kV3;
#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
// former V2 (fixed dual interface) setup expressed as V3
constexpr int kMainModeId = chip_mode_ids::kV3;
# ifdef WIFI_HIDL_FEATURE_DISABLE_AP
# ifdef WIFI_HIDL_FEATURE_AWARE
// 1 STA + 1 of (P2P or NAN)
# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
# else
// 1 STA + 1 P2P
# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
# endif
# else
# ifdef WIFI_HIDL_FEATURE_AWARE
// (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
{{{STA}, 1}, {{P2P, NAN}, 1}}
# else
// (1 STA + 1 AP) or (1 STA + 1 P2P)
# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
{{{STA}, 1}, {{P2P}, 1}}
# endif
# endif
#else
// V1 (fixed single interface, dual-mode chip)
constexpr int kMainModeId = chip_mode_ids::kV1Sta;
# ifdef WIFI_HIDL_FEATURE_AWARE
// 1 STA + 1 of (P2P or NAN)
# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
# else
// 1 STA + 1 P2P
# define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
# endif
# ifndef WIFI_HIDL_FEATURE_DISABLE_AP
# define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
# endif
#endif
// clang-format on
// Convert from the legacy format (used by the WIFI_HAL_INTERFACE_COMBINATIONS
// config variable) to a list of ChipConcurrencyCombination objects.
std::vector<IWifiChip::ChipConcurrencyCombination> legacyToChipConcurrencyComboList(
std::vector<std::vector<IWifiChip::ChipConcurrencyCombinationLimit>> legacyLimits) {
std::vector<IWifiChip::ChipConcurrencyCombination> combos;
for (auto& legacyLimit : legacyLimits) {
IWifiChip::ChipConcurrencyCombination combo = {legacyLimit};
combos.push_back(combo);
}
return combos;
}
#define STA IfaceConcurrencyType::STA
#define AP IfaceConcurrencyType::AP
#define AP_BRIDGED IfaceConcurrencyType::AP_BRIDGED
#define P2P IfaceConcurrencyType::P2P
#define NAN IfaceConcurrencyType::NAN_IFACE
static const std::vector<IWifiChip::ChipMode> kChipModesPrimary{
{kMainModeId, legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS})},
#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
{chip_mode_ids::kV1Ap,
legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
#endif
};
static const std::vector<IWifiChip::ChipMode> kChipModesSecondary{
#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
{chip_mode_ids::kV3,
legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
#endif
};
constexpr char kDebugPresetInterfaceCombinationIdxProperty[] =
"persist.vendor.debug.wifi.hal.preset_interface_combination_idx";
// List of pre-defined concurrency combinations that can be enabled at runtime via
// setting the property: "kDebugPresetInterfaceCombinationIdxProperty" to the
// corresponding index value.
static const std::vector<std::pair<std::string, std::vector<IWifiChip::ChipMode>>> kDebugChipModes{
// Legacy combination - No STA/AP concurrencies.
// 0 - (1 AP) or (1 STA + 1 of (P2P or NAN))
{"No STA/AP Concurrency",
{{kMainModeId,
legacyToChipConcurrencyComboList({{{{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
// STA + AP concurrency
// 1 - (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
{"STA + AP Concurrency",
{{kMainModeId, legacyToChipConcurrencyComboList(
{{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
// STA + STA concurrency
// 2 - (1 STA + 1 AP) or (2 STA + 1 of (P2P or NAN))
{"Dual STA Concurrency",
{{kMainModeId, legacyToChipConcurrencyComboList(
{{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
// AP + AP + STA concurrency
// 3 - (1 STA + 2 AP) or (1 STA + 1 of (P2P or NAN))
{"Dual AP Concurrency",
{{kMainModeId, legacyToChipConcurrencyComboList(
{{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
// STA + STA concurrency and AP + AP + STA concurrency
// 4 - (1 STA + 2 AP) or (2 STA + 1 of (P2P or NAN))
{"Dual STA & Dual AP Concurrency",
{{kMainModeId, legacyToChipConcurrencyComboList(
{{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
// STA + STA concurrency
// 5 - (1 STA + 1 AP (bridged or single) | P2P | NAN), or (2 STA))
{"Dual STA or STA plus single other interface",
{{kMainModeId, legacyToChipConcurrencyComboList(
{{{{STA}, 1}, {{P2P, NAN, AP, AP_BRIDGED}, 1}}, {{{STA}, 2}}})}}}};
#undef STA
#undef AP
#undef AP_BRIDGED
#undef P2P
#undef NAN
#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
#pragma message \
"WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
"'config_wifi_ap_randomization_supported' in " \
"frameworks/base/core/res/res/values/config.xml in the device overlay " \
"instead"
#endif // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
WifiFeatureFlags::WifiFeatureFlags() {}
std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModesForPrimary() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
auto res = property_get(kDebugPresetInterfaceCombinationIdxProperty, buffer.data(), nullptr);
// Debug property not set, use the device preset concurrency combination.
if (res <= 0) return kChipModesPrimary;
// Debug property set, use one of the debug preset concurrency combination.
unsigned long idx = std::stoul(buffer.data());
if (idx >= kDebugChipModes.size()) {
LOG(ERROR) << "Invalid index set in property: "
<< kDebugPresetInterfaceCombinationIdxProperty;
return kChipModesPrimary;
}
std::string name;
std::vector<IWifiChip::ChipMode> chip_modes;
std::tie(name, chip_modes) = kDebugChipModes[idx];
LOG(INFO) << "Using debug chip mode: <" << name
<< "> set via property: " << kDebugPresetInterfaceCombinationIdxProperty;
return chip_modes;
}
std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(bool is_primary) {
return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary;
}
} // namespace feature_flags
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,56 @@
/*
* 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.
*/
#ifndef WIFI_FEATURE_FLAGS_H_
#define WIFI_FEATURE_FLAGS_H_
#include <aidl/android/hardware/wifi/IWifiChip.h>
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace feature_flags {
namespace chip_mode_ids {
// These mode ID's should be unique (even across combo versions). Refer to
// handleChipConfiguration() for its usage.
constexpr uint32_t kInvalid = UINT32_MAX;
// Mode ID's for V1
constexpr uint32_t kV1Sta = 0;
constexpr uint32_t kV1Ap = 1;
// Mode ID for V3
constexpr uint32_t kV3 = 3;
} // namespace chip_mode_ids
class WifiFeatureFlags {
public:
WifiFeatureFlags();
virtual ~WifiFeatureFlags() = default;
virtual std::vector<IWifiChip::ChipMode> getChipModes(bool is_primary);
private:
std::vector<IWifiChip::ChipMode> getChipModesForPrimary();
};
} // namespace feature_flags
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_FEATURE_FLAGS_H_

View File

@@ -0,0 +1,174 @@
/*
* 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <net/if.h>
#include <private/android_filesystem_config.h>
#include <cstddef>
#include <iostream>
#include <limits>
#include <random>
#include "wifi_iface_util.h"
namespace {
// Constants to set the local bit & clear the multicast bit.
constexpr uint8_t kMacAddressMulticastMask = 0x01;
constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace iface_util {
WifiIfaceUtil::WifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
: iface_tool_(iface_tool),
legacy_hal_(legacy_hal),
random_mac_address_(nullptr),
event_handlers_map_() {}
std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(const std::string& iface_name) {
return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
}
bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
const std::array<uint8_t, 6>& mac) {
#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
legacy_hal::wifi_error legacy_status;
uint64_t legacy_feature_set;
std::tie(legacy_status, legacy_feature_set) =
legacy_hal_.lock()->getSupportedFeatureSet(iface_name);
if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
LOG(ERROR) << "SetUpState(false) failed.";
return false;
}
#endif
bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac);
#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready.";
// Wait for driver ready and try to set iface UP again
if (legacy_hal_.lock()->waitForDriverReady() != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "SetUpState(true) wait for driver ready failed.";
return false;
}
if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
LOG(ERROR) << "SetUpState(true) failed after retry.";
return false;
}
}
#endif
IfaceEventHandlers event_handlers = {};
const auto it = event_handlers_map_.find(iface_name);
if (it != event_handlers_map_.end()) {
event_handlers = it->second;
}
if (event_handlers.on_state_toggle_off_on != nullptr) {
event_handlers.on_state_toggle_off_on(iface_name);
}
if (!success) {
LOG(ERROR) << "SetMacAddress failed on " << iface_name;
} else {
LOG(DEBUG) << "SetMacAddress succeeded on " << iface_name;
}
return success;
}
std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
if (random_mac_address_) {
return *random_mac_address_.get();
}
random_mac_address_ = std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
return *random_mac_address_.get();
}
void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
IfaceEventHandlers handlers) {
event_handlers_map_[iface_name] = handlers;
}
void WifiIfaceUtil::unregisterIfaceEventHandlers(const std::string& iface_name) {
event_handlers_map_.erase(iface_name);
}
std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
std::array<uint8_t, 6> address = {};
std::random_device rd;
std::default_random_engine engine(rd());
std::uniform_int_distribution<uint8_t> dist(std::numeric_limits<uint8_t>::min(),
std::numeric_limits<uint8_t>::max());
for (size_t i = 0; i < address.size(); i++) {
address[i] = dist(engine);
}
// Set the local bit and clear the multicast bit.
address[0] |= kMacAddressLocallyAssignedMask;
address[0] &= ~kMacAddressMulticastMask;
return address;
}
bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) {
if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) {
LOG(ERROR) << "SetUpState to " << request_up << " failed";
return false;
}
return true;
}
unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) {
return if_nametoindex(iface_name.c_str());
}
bool WifiIfaceUtil::createBridge(const std::string& br_name) {
if (!iface_tool_.lock()->createBridge(br_name)) {
return false;
}
if (!iface_tool_.lock()->SetUpState(br_name.c_str(), true)) {
LOG(ERROR) << "bridge SetUpState(true) failed.";
}
return true;
}
bool WifiIfaceUtil::deleteBridge(const std::string& br_name) {
if (!iface_tool_.lock()->SetUpState(br_name.c_str(), false)) {
LOG(INFO) << "SetUpState(false) failed for bridge=" << br_name.c_str();
}
return iface_tool_.lock()->deleteBridge(br_name);
}
bool WifiIfaceUtil::addIfaceToBridge(const std::string& br_name, const std::string& if_name) {
return iface_tool_.lock()->addIfaceToBridge(br_name, if_name);
}
bool WifiIfaceUtil::removeIfaceFromBridge(const std::string& br_name, const std::string& if_name) {
return iface_tool_.lock()->removeIfaceFromBridge(br_name, if_name);
}
} // namespace iface_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,84 @@
/*
* 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.
*/
#ifndef WIFI_IFACE_UTIL_H_
#define WIFI_IFACE_UTIL_H_
#include <aidl/android/hardware/wifi/IWifi.h>
#include <wifi_system/interface_tool.h>
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace iface_util {
// Iface event handlers.
struct IfaceEventHandlers {
// Callback to be invoked when the iface is set down & up for MAC address
// change.
std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
};
/**
* Util class for common iface operations.
*/
class WifiIfaceUtil {
public:
WifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
virtual ~WifiIfaceUtil() = default;
virtual std::array<uint8_t, 6> getFactoryMacAddress(const std::string& iface_name);
virtual bool setMacAddress(const std::string& iface_name, const std::array<uint8_t, 6>& mac);
// Get or create a random MAC address. The MAC address returned from
// this method will remain the same throughout the lifetime of the HAL
// daemon. (So, changes on every reboot)
virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
// Register for any iface event callbacks for the provided interface.
virtual void registerIfaceEventHandlers(const std::string& iface_name,
IfaceEventHandlers handlers);
virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
virtual bool setUpState(const std::string& iface_name, bool request_up);
virtual unsigned ifNameToIndex(const std::string& iface_name);
virtual bool createBridge(const std::string& br_name);
virtual bool deleteBridge(const std::string& br_name);
virtual bool addIfaceToBridge(const std::string& br_name, const std::string& if_name);
virtual bool removeIfaceFromBridge(const std::string& br_name, const std::string& if_name);
// Get a random MAC address.
virtual std::array<uint8_t, 6> createRandomMacAddress();
private:
std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
std::map<std::string, IfaceEventHandlers> event_handlers_map_;
};
} // namespace iface_util
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_IFACE_UTIL_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,738 @@
/*
* 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.
*/
#ifndef WIFI_LEGACY_HAL_H_
#define WIFI_LEGACY_HAL_H_
#include <hardware_legacy/wifi_hal.h>
#include <wifi_system/interface_tool.h>
#include <condition_variable>
#include <functional>
#include <map>
#include <mutex>
#include <thread>
#include <vector>
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
// This is in a separate namespace to prevent typename conflicts between
// the legacy HAL types and the AIDL interface types.
namespace legacy_hal {
// Import all the types defined inside the legacy HAL header files into this
// namespace.
using ::chre_nan_rtt_state;
using ::frame_info;
using ::frame_type;
using ::FRAME_TYPE_80211_MGMT;
using ::FRAME_TYPE_ETHERNET_II;
using ::FRAME_TYPE_UNKNOWN;
using ::fw_roaming_state_t;
using ::mac_addr;
using ::NAN_CHANNEL_24G_BAND;
using ::NAN_CHANNEL_5G_BAND_HIGH;
using ::NAN_CHANNEL_5G_BAND_LOW;
using ::NAN_DISABLE_RANGE_REPORT;
using ::NAN_DO_NOT_USE_SRF;
using ::NAN_DP_CHANNEL_NOT_REQUESTED;
using ::NAN_DP_CONFIG_NO_SECURITY;
using ::NAN_DP_CONFIG_SECURITY;
using ::NAN_DP_END;
using ::NAN_DP_FORCE_CHANNEL_SETUP;
using ::NAN_DP_INITIATOR_RESPONSE;
using ::NAN_DP_INTERFACE_CREATE;
using ::NAN_DP_INTERFACE_DELETE;
using ::NAN_DP_REQUEST_ACCEPT;
using ::NAN_DP_REQUEST_CHANNEL_SETUP;
using ::NAN_DP_REQUEST_REJECT;
using ::NAN_DP_RESPONDER_RESPONSE;
using ::NAN_GET_CAPABILITIES;
using ::NAN_MATCH_ALG_MATCH_CONTINUOUS;
using ::NAN_MATCH_ALG_MATCH_NEVER;
using ::NAN_MATCH_ALG_MATCH_ONCE;
using ::NAN_PUBLISH_TYPE_SOLICITED;
using ::NAN_PUBLISH_TYPE_UNSOLICITED;
using ::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
using ::NAN_RANGING_AUTO_RESPONSE_DISABLE;
using ::NAN_RANGING_AUTO_RESPONSE_ENABLE;
using ::NAN_RANGING_DISABLE;
using ::NAN_RANGING_ENABLE;
using ::NAN_RESPONSE_BEACON_SDF_PAYLOAD;
using ::NAN_RESPONSE_CONFIG;
using ::NAN_RESPONSE_DISABLED;
using ::NAN_RESPONSE_ENABLED;
using ::NAN_RESPONSE_ERROR;
using ::NAN_RESPONSE_PUBLISH;
using ::NAN_RESPONSE_PUBLISH_CANCEL;
using ::NAN_RESPONSE_STATS;
using ::NAN_RESPONSE_SUBSCRIBE;
using ::NAN_RESPONSE_SUBSCRIBE_CANCEL;
using ::NAN_RESPONSE_TCA;
using ::NAN_RESPONSE_TRANSMIT_FOLLOWUP;
using ::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
using ::NAN_SECURITY_KEY_INPUT_PMK;
using ::NAN_SERVICE_ACCEPT_POLICY_ALL;
using ::NAN_SERVICE_ACCEPT_POLICY_NONE;
using ::NAN_SRF_ATTR_BLOOM_FILTER;
using ::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
using ::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
using ::NAN_SRF_INCLUDE_RESPOND;
using ::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
using ::NAN_SSI_REQUIRED_IN_MATCH_IND;
using ::NAN_STATUS_ALREADY_ENABLED;
using ::NAN_STATUS_FOLLOWUP_QUEUE_FULL;
using ::NAN_STATUS_INTERNAL_FAILURE;
using ::NAN_STATUS_INVALID_NDP_ID;
using ::NAN_STATUS_INVALID_PARAM;
using ::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
using ::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID;
using ::NAN_STATUS_NAN_NOT_ALLOWED;
using ::NAN_STATUS_NO_OTA_ACK;
using ::NAN_STATUS_NO_RESOURCE_AVAILABLE;
using ::NAN_STATUS_PROTOCOL_FAILURE;
using ::NAN_STATUS_SUCCESS;
using ::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
using ::NAN_SUBSCRIBE_TYPE_ACTIVE;
using ::NAN_SUBSCRIBE_TYPE_PASSIVE;
using ::NAN_TRANSMIT_IN_DW;
using ::NAN_TRANSMIT_IN_FAW;
using ::NAN_TX_PRIORITY_HIGH;
using ::NAN_TX_PRIORITY_NORMAL;
using ::NAN_TX_TYPE_BROADCAST;
using ::NAN_TX_TYPE_UNICAST;
using ::NAN_USE_SRF;
using ::NanBeaconSdfPayloadInd;
using ::NanCapabilities;
using ::NanChannelInfo;
using ::NanConfigRequest;
using ::NanDataPathChannelCfg;
using ::NanDataPathConfirmInd;
using ::NanDataPathEndInd;
using ::NanDataPathIndicationResponse;
using ::NanDataPathInitiatorRequest;
using ::NanDataPathRequestInd;
using ::NanDataPathScheduleUpdateInd;
using ::NanDisabledInd;
using ::NanDiscEngEventInd;
using ::NanEnableRequest;
using ::NanFollowupInd;
using ::NanMatchAlg;
using ::NanMatchExpiredInd;
using ::NanMatchInd;
using ::NanPublishCancelRequest;
using ::NanPublishRequest;
using ::NanPublishTerminatedInd;
using ::NanPublishType;
using ::NanRangeReportInd;
using ::NanRangeRequestInd;
using ::NanResponseMsg;
using ::NanSRFType;
using ::NanStatusType;
using ::NanSubscribeCancelRequest;
using ::NanSubscribeRequest;
using ::NanSubscribeTerminatedInd;
using ::NanSubscribeType;
using ::NanTransmitFollowupInd;
using ::NanTransmitFollowupRequest;
using ::NanTxType;
using ::ROAMING_DISABLE;
using ::ROAMING_ENABLE;
using ::RTT_PEER_AP;
using ::RTT_PEER_NAN;
using ::RTT_PEER_P2P_CLIENT;
using ::RTT_PEER_P2P_GO;
using ::RTT_PEER_STA;
using ::rtt_peer_type;
using ::RTT_STATUS_ABORTED;
using ::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL;
using ::RTT_STATUS_FAIL_BUSY_TRY_LATER;
using ::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE;
using ::RTT_STATUS_FAIL_INVALID_TS;
using ::RTT_STATUS_FAIL_NO_CAPABILITY;
using ::RTT_STATUS_FAIL_NO_RSP;
using ::RTT_STATUS_FAIL_NOT_SCHEDULED_YET;
using ::RTT_STATUS_FAIL_PROTOCOL;
using ::RTT_STATUS_FAIL_REJECTED;
using ::RTT_STATUS_FAIL_SCHEDULE;
using ::RTT_STATUS_FAIL_TM_TIMEOUT;
using ::RTT_STATUS_FAILURE;
using ::RTT_STATUS_INVALID_REQ;
using ::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
using ::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE;
using ::RTT_STATUS_NO_WIFI;
using ::RTT_STATUS_SUCCESS;
using ::RTT_TYPE_1_SIDED;
using ::RTT_TYPE_2_SIDED;
using ::RX_PKT_FATE_DRV_DROP_FILTER;
using ::RX_PKT_FATE_DRV_DROP_INVALID;
using ::RX_PKT_FATE_DRV_DROP_NOBUFS;
using ::RX_PKT_FATE_DRV_DROP_OTHER;
using ::RX_PKT_FATE_DRV_QUEUED;
using ::RX_PKT_FATE_FW_DROP_FILTER;
using ::RX_PKT_FATE_FW_DROP_INVALID;
using ::RX_PKT_FATE_FW_DROP_NOBUFS;
using ::RX_PKT_FATE_FW_DROP_OTHER;
using ::RX_PKT_FATE_FW_QUEUED;
using ::RX_PKT_FATE_SUCCESS;
using ::ssid_t;
using ::transaction_id;
using ::TX_PKT_FATE_ACKED;
using ::TX_PKT_FATE_DRV_DROP_INVALID;
using ::TX_PKT_FATE_DRV_DROP_NOBUFS;
using ::TX_PKT_FATE_DRV_DROP_OTHER;
using ::TX_PKT_FATE_DRV_QUEUED;
using ::TX_PKT_FATE_FW_DROP_INVALID;
using ::TX_PKT_FATE_FW_DROP_NOBUFS;
using ::TX_PKT_FATE_FW_DROP_OTHER;
using ::TX_PKT_FATE_FW_QUEUED;
using ::TX_PKT_FATE_SENT;
using ::WIFI_AC_BE;
using ::WIFI_AC_BK;
using ::WIFI_AC_VI;
using ::WIFI_AC_VO;
using ::WIFI_ANTENNA_1X1;
using ::WIFI_ANTENNA_2X2;
using ::WIFI_ANTENNA_3X3;
using ::WIFI_ANTENNA_4X4;
using ::WIFI_ANTENNA_UNSPECIFIED;
using ::wifi_band;
using ::WIFI_BAND_A;
using ::WIFI_BAND_A_DFS;
using ::WIFI_BAND_A_WITH_DFS;
using ::WIFI_BAND_ABG;
using ::WIFI_BAND_ABG_WITH_DFS;
using ::WIFI_BAND_BG;
using ::WIFI_BAND_UNSPECIFIED;
using ::wifi_cached_scan_report;
using ::wifi_cached_scan_results;
using ::WIFI_CHAN_WIDTH_10;
using ::WIFI_CHAN_WIDTH_160;
using ::WIFI_CHAN_WIDTH_20;
using ::WIFI_CHAN_WIDTH_320;
using ::WIFI_CHAN_WIDTH_40;
using ::WIFI_CHAN_WIDTH_5;
using ::WIFI_CHAN_WIDTH_80;
using ::WIFI_CHAN_WIDTH_80P80;
using ::WIFI_CHAN_WIDTH_INVALID;
using ::wifi_channel_info;
using ::wifi_channel_stat;
using ::wifi_channel_width;
using ::wifi_coex_restriction;
using ::wifi_coex_unsafe_channel;
using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
using ::wifi_error;
using ::WIFI_ERROR_BUSY;
using ::WIFI_ERROR_INVALID_ARGS;
using ::WIFI_ERROR_INVALID_REQUEST_ID;
using ::WIFI_ERROR_NONE;
using ::WIFI_ERROR_NOT_AVAILABLE;
using ::WIFI_ERROR_NOT_SUPPORTED;
using ::WIFI_ERROR_OUT_OF_MEMORY;
using ::WIFI_ERROR_TIMED_OUT;
using ::WIFI_ERROR_TOO_MANY_REQUESTS;
using ::WIFI_ERROR_UNINITIALIZED;
using ::WIFI_ERROR_UNKNOWN;
using ::wifi_gscan_capabilities;
using ::wifi_hal_fn;
using ::wifi_information_element;
using ::WIFI_INTERFACE_IBSS;
using ::WIFI_INTERFACE_MESH;
using ::wifi_interface_mode;
using ::WIFI_INTERFACE_NAN;
using ::WIFI_INTERFACE_P2P_CLIENT;
using ::WIFI_INTERFACE_P2P_GO;
using ::WIFI_INTERFACE_SOFTAP;
using ::WIFI_INTERFACE_STA;
using ::WIFI_INTERFACE_TDLS;
using ::wifi_interface_type;
using ::WIFI_INTERFACE_TYPE_AP;
using ::WIFI_INTERFACE_TYPE_NAN;
using ::WIFI_INTERFACE_TYPE_P2P;
using ::WIFI_INTERFACE_TYPE_STA;
using ::WIFI_INTERFACE_UNKNOWN;
using ::wifi_latency_mode;
using ::WIFI_LATENCY_MODE_LOW;
using ::WIFI_LATENCY_MODE_NORMAL;
using ::wifi_lci_information;
using ::wifi_lcr_information;
using ::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
using ::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
using ::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
using ::WIFI_LOGGER_PACKET_FATE_SUPPORTED;
using ::WIFI_LOGGER_POWER_EVENT_SUPPORTED;
using ::WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
using ::WIFI_MOTION_EXPECTED;
using ::WIFI_MOTION_NOT_EXPECTED;
using ::wifi_motion_pattern;
using ::WIFI_MOTION_UNKNOWN;
using ::wifi_multi_sta_use_case;
using ::wifi_power_scenario;
using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
using ::WIFI_POWER_SCENARIO_VOICE_CALL;
using ::wifi_radio_combination;
using ::wifi_radio_combination_matrix;
using ::wifi_radio_configuration;
using ::wifi_rate;
using ::wifi_request_id;
using ::wifi_ring_buffer_status;
using ::wifi_roaming_capabilities;
using ::wifi_roaming_config;
using ::wifi_rtt_bw;
using ::WIFI_RTT_BW_10;
using ::WIFI_RTT_BW_160;
using ::WIFI_RTT_BW_20;
using ::WIFI_RTT_BW_320;
using ::WIFI_RTT_BW_40;
using ::WIFI_RTT_BW_5;
using ::WIFI_RTT_BW_80;
using ::wifi_rtt_capabilities;
using ::wifi_rtt_config;
using ::wifi_rtt_preamble;
using ::WIFI_RTT_PREAMBLE_EHT;
using ::WIFI_RTT_PREAMBLE_HE;
using ::WIFI_RTT_PREAMBLE_HT;
using ::WIFI_RTT_PREAMBLE_LEGACY;
using ::WIFI_RTT_PREAMBLE_VHT;
using ::wifi_rtt_responder;
using ::wifi_rtt_result;
using ::wifi_rtt_status;
using ::wifi_rtt_type;
using ::wifi_rx_packet_fate;
using ::wifi_rx_report;
using ::wifi_scan_bucket_spec;
using ::wifi_scan_cmd_params;
using ::WIFI_SCAN_FLAG_INTERRUPTED;
using ::wifi_scan_result;
using ::WIFI_SUCCESS;
using ::wifi_tx_packet_fate;
using ::wifi_tx_report;
using ::wifi_usable_channel;
using ::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
using ::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
using ::WLAN_MAC_2_4_BAND;
using ::WLAN_MAC_5_0_BAND;
using ::WLAN_MAC_60_0_BAND;
using ::WLAN_MAC_6_0_BAND;
// APF capabilities supported by the iface.
struct PacketFilterCapabilities {
uint32_t version;
uint32_t max_len;
};
// WARNING: We don't care about the variable sized members of either
// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
// to escape the compiler warnings regarding this.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
// into a separate return element to avoid passing pointers around.
struct LinkLayerRadioStats {
wifi_radio_stat stats;
std::vector<uint32_t> tx_time_per_levels;
std::vector<wifi_channel_stat> channel_stats;
};
struct WifiPeerInfo {
wifi_peer_info peer_info;
std::vector<wifi_rate_stat> rate_stats;
};
struct LinkLayerStats {
wifi_iface_stat iface;
std::vector<LinkLayerRadioStats> radios;
std::vector<WifiPeerInfo> peers;
};
#pragma GCC diagnostic pop
// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
// API. Separate that out into a separate return elements to avoid passing
// pointers around.
struct WakeReasonStats {
WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
std::vector<uint32_t> cmd_event_wake_cnt;
std::vector<uint32_t> driver_fw_local_wake_cnt;
};
// NAN response and event callbacks struct.
struct NanCallbackHandlers {
// NotifyResponse invoked to notify the status of the Request.
std::function<void(transaction_id, const NanResponseMsg&)> on_notify_response;
// Various event callbacks.
std::function<void(const NanPublishTerminatedInd&)> on_event_publish_terminated;
std::function<void(const NanMatchInd&)> on_event_match;
std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
std::function<void(const NanSubscribeTerminatedInd&)> on_event_subscribe_terminated;
std::function<void(const NanFollowupInd&)> on_event_followup;
std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
std::function<void(const NanDisabledInd&)> on_event_disabled;
std::function<void(const NanTCAInd&)> on_event_tca;
std::function<void(const NanBeaconSdfPayloadInd&)> on_event_beacon_sdf_payload;
std::function<void(const NanDataPathRequestInd&)> on_event_data_path_request;
std::function<void(const NanDataPathConfirmInd&)> on_event_data_path_confirm;
std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
std::function<void(const NanTransmitFollowupInd&)> on_event_transmit_follow_up;
std::function<void(const NanRangeRequestInd&)> on_event_range_request;
std::function<void(const NanRangeReportInd&)> on_event_range_report;
std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
};
// Full scan results contain IE info and are hence passed by reference, to
// preserve the variable length array member |ie_data|. Callee must not retain
// the pointer.
using on_gscan_full_result_callback =
std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
// These scan results don't contain any IE info, so no need to pass by
// reference.
using on_gscan_results_callback =
std::function<void(wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
// Invoked when the rssi value breaches the thresholds set.
using on_rssi_threshold_breached_callback =
std::function<void(wifi_request_id, std::array<uint8_t, ETH_ALEN>, int8_t)>;
// Callback for RTT range request results.
// Rtt results contain IE info and are hence passed by reference, to
// preserve the |LCI| and |LCR| pointers. Callee must not retain
// the pointer.
using on_rtt_results_callback =
std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
// Callback for ring buffer data.
using on_ring_buffer_data_callback = std::function<void(
const std::string&, const std::vector<uint8_t>&, const wifi_ring_buffer_status&)>;
// Callback for alerts.
using on_error_alert_callback = std::function<void(int32_t, const std::vector<uint8_t>&)>;
// Callback for subsystem restart
using on_subsystem_restart_callback = std::function<void(const std::string&)>;
// Struct for the mac info from the legacy HAL. This is a cleaner version
// of the |wifi_mac_info| & |wifi_iface_info|.
typedef struct {
std::string name;
wifi_channel channel;
} WifiIfaceInfo;
typedef struct {
uint32_t wlan_mac_id;
/* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
uint32_t mac_band;
/* Represents the connected Wi-Fi interfaces associated with each MAC */
std::vector<WifiIfaceInfo> iface_infos;
} WifiMacInfo;
// Callback for radio mode change
using on_radio_mode_change_callback = std::function<void(const std::vector<WifiMacInfo>&)>;
// TWT response and event callbacks struct.
struct TwtCallbackHandlers {
// Callback for TWT setup response
std::function<void(const TwtSetupResponse&)> on_setup_response;
// Callback for TWT teardown completion
std::function<void(const TwtTeardownCompletion&)> on_teardown_completion;
// Callback for TWT info frame received event
std::function<void(const TwtInfoFrameReceived&)> on_info_frame_received;
// Callback for TWT notification from the device
std::function<void(const TwtDeviceNotify&)> on_device_notify;
};
// CHRE response and event callbacks struct.
struct ChreCallbackHandlers {
// Callback for CHRE NAN RTT
std::function<void(chre_nan_rtt_state)> on_wifi_chre_nan_rtt_state;
};
// Cached Scan Results response and event callbacks struct.
struct CachedScanResultsCallbackHandlers {
// Callback for Cached Scan Results
std::function<void(wifi_cached_scan_report*)> on_cached_scan_results;
};
/**
* Class that encapsulates all legacy HAL interactions.
* This class manages the lifetime of the event loop thread used by legacy HAL.
*
* Note: There will only be a single instance of this class created in the Wifi
* object and will be valid for the lifetime of the process.
*/
class WifiLegacyHal {
public:
WifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
const wifi_hal_fn& fn, bool is_primary);
virtual ~WifiLegacyHal() = default;
// Initialize the legacy HAL function table.
virtual wifi_error initialize();
// Start the legacy HAL and the event looper thread.
virtual wifi_error start();
// Deinitialize the legacy HAL and wait for the event loop thread to exit
// using a predefined timeout.
virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
const std::function<void()>& on_complete_callback);
virtual wifi_error waitForDriverReady();
// Checks if legacy HAL has successfully started
bool isStarted();
// Wrappers for all the functions in the legacy HAL function table.
virtual std::pair<wifi_error, std::string> getDriverVersion(const std::string& iface_name);
virtual std::pair<wifi_error, std::string> getFirmwareVersion(const std::string& iface_name);
std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
const std::string& iface_name);
std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
const std::string& iface_name);
virtual std::pair<wifi_error, uint64_t> getSupportedFeatureSet(const std::string& iface_name);
// APF functions.
std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
const std::string& iface_name);
wifi_error setPacketFilter(const std::string& iface_name, const std::vector<uint8_t>& program);
std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
const std::string& iface_name);
// Gscan functions.
std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
const std::string& iface_name);
// These API's provides a simplified interface over the legacy Gscan API's:
// a) All scan events from the legacy HAL API other than the
// |WIFI_SCAN_FAILED| are treated as notification of results.
// This method then retrieves the cached scan results from the legacy
// HAL API and triggers the externally provided
// |on_results_user_callback| on success.
// b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
// results
// Triggers the externally provided |on_failure_user_callback|.
// c) Full scan result event triggers the externally provided
// |on_full_result_user_callback|.
wifi_error startGscan(const std::string& iface_name, wifi_request_id id,
const wifi_scan_cmd_params& params,
const std::function<void(wifi_request_id)>& on_failure_callback,
const on_gscan_results_callback& on_results_callback,
const on_gscan_full_result_callback& on_full_result_callback);
wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
const std::string& iface_name, wifi_band band);
virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
// Link layer stats functions.
wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
wifi_error disableLinkLayerStats(const std::string& iface_name);
std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(const std::string& iface_name);
// RSSI monitor functions.
wifi_error startRssiMonitoring(
const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
const on_rssi_threshold_breached_callback& on_threshold_breached_callback);
wifi_error stopRssiMonitoring(const std::string& iface_name, wifi_request_id id);
std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
const std::string& iface_name);
wifi_error configureRoaming(const std::string& iface_name, const wifi_roaming_config& config);
wifi_error enableFirmwareRoaming(const std::string& iface_name, fw_roaming_state_t state);
wifi_error configureNdOffload(const std::string& iface_name, bool enable);
wifi_error startSendingOffloadedPacket(const std::string& iface_name, int32_t cmd_id,
uint16_t ether_type,
const std::vector<uint8_t>& ip_packet_data,
const std::array<uint8_t, 6>& src_address,
const std::array<uint8_t, 6>& dst_address,
int32_t period_in_ms);
wifi_error stopSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id);
virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
wifi_power_scenario scenario);
virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
wifi_error setLatencyMode(const std::string& iface_name, wifi_latency_mode mode);
wifi_error setThermalMitigationMode(wifi_thermal_mode mode, uint32_t completion_window);
wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
uint32_t access_category);
wifi_error resetDscpToAccessCategoryMapping();
// Logger/debug functions.
std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(const std::string& iface_name);
wifi_error startPktFateMonitoring(const std::string& iface_name);
std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(const std::string& iface_name);
std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(const std::string& iface_name);
std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(const std::string& iface_name);
wifi_error registerRingBufferCallbackHandler(
const std::string& iface_name, const on_ring_buffer_data_callback& on_data_callback);
wifi_error deregisterRingBufferCallbackHandler(const std::string& iface_name);
virtual wifi_error registerSubsystemRestartCallbackHandler(
const on_subsystem_restart_callback& on_restart_callback);
std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> getRingBuffersStatus(
const std::string& iface_name);
wifi_error startRingBufferLogging(const std::string& iface_name, const std::string& ring_name,
uint32_t verbose_level, uint32_t max_interval_sec,
uint32_t min_data_size);
wifi_error getRingBufferData(const std::string& iface_name, const std::string& ring_name);
wifi_error registerErrorAlertCallbackHandler(const std::string& iface_name,
const on_error_alert_callback& on_alert_callback);
wifi_error deregisterErrorAlertCallbackHandler(const std::string& iface_name);
// Radio mode functions.
virtual wifi_error registerRadioModeChangeCallbackHandler(
const std::string& iface_name,
const on_radio_mode_change_callback& on_user_change_callback);
// RTT functions.
wifi_error startRttRangeRequest(const std::string& iface_name, wifi_request_id id,
const std::vector<wifi_rtt_config>& rtt_configs,
const on_rtt_results_callback& on_results_callback);
wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id,
const std::vector<std::array<uint8_t, ETH_ALEN>>& mac_addrs);
std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(const std::string& iface_name);
std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(const std::string& iface_name);
wifi_error enableRttResponder(const std::string& iface_name, wifi_request_id id,
const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
const wifi_rtt_responder& info);
wifi_error disableRttResponder(const std::string& iface_name, wifi_request_id id);
wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
const wifi_lci_information& info);
wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
const wifi_lcr_information& info);
// NAN functions.
virtual wifi_error nanRegisterCallbackHandlers(const std::string& iface_name,
const NanCallbackHandlers& callbacks);
wifi_error nanEnableRequest(const std::string& iface_name, transaction_id id,
const NanEnableRequest& msg);
virtual wifi_error nanDisableRequest(const std::string& iface_name, transaction_id id);
wifi_error nanPublishRequest(const std::string& iface_name, transaction_id id,
const NanPublishRequest& msg);
wifi_error nanPublishCancelRequest(const std::string& iface_name, transaction_id id,
const NanPublishCancelRequest& msg);
wifi_error nanSubscribeRequest(const std::string& iface_name, transaction_id id,
const NanSubscribeRequest& msg);
wifi_error nanSubscribeCancelRequest(const std::string& iface_name, transaction_id id,
const NanSubscribeCancelRequest& msg);
wifi_error nanTransmitFollowupRequest(const std::string& iface_name, transaction_id id,
const NanTransmitFollowupRequest& msg);
wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
const NanStatsRequest& msg);
wifi_error nanConfigRequest(const std::string& iface_name, transaction_id id,
const NanConfigRequest& msg);
wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
const NanTCARequest& msg);
wifi_error nanBeaconSdfPayloadRequest(const std::string& iface_name, transaction_id id,
const NanBeaconSdfPayloadRequest& msg);
std::pair<wifi_error, NanVersion> nanGetVersion();
wifi_error nanGetCapabilities(const std::string& iface_name, transaction_id id);
wifi_error nanDataInterfaceCreate(const std::string& iface_name, transaction_id id,
const std::string& data_iface_name);
virtual wifi_error nanDataInterfaceDelete(const std::string& iface_name, transaction_id id,
const std::string& data_iface_name);
wifi_error nanDataRequestInitiator(const std::string& iface_name, transaction_id id,
const NanDataPathInitiatorRequest& msg);
wifi_error nanDataIndicationResponse(const std::string& iface_name, transaction_id id,
const NanDataPathIndicationResponse& msg);
wifi_error nanDataEnd(const std::string& iface_name, transaction_id id, uint32_t ndpInstanceId);
// AP functions.
wifi_error setCountryCode(const std::string& iface_name, const std::array<uint8_t, 2> code);
// Interface functions.
virtual wifi_error createVirtualInterface(const std::string& ifname,
wifi_interface_type iftype);
virtual wifi_error deleteVirtualInterface(const std::string& ifname);
virtual wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
// STA + STA functions
virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
// Coex functions.
virtual wifi_error setCoexUnsafeChannels(std::vector<wifi_coex_unsafe_channel> unsafe_channels,
uint32_t restrictions);
wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode);
wifi_error twtRegisterHandler(const std::string& iface_name,
const TwtCallbackHandlers& handler);
std::pair<wifi_error, TwtCapabilitySet> twtGetCapability(const std::string& iface_name);
wifi_error twtSetupRequest(const std::string& iface_name, const TwtSetupRequest& msg);
wifi_error twtTearDownRequest(const std::string& iface_name, const TwtTeardownRequest& msg);
wifi_error twtInfoFrameRequest(const std::string& iface_name, const TwtInfoFrameRequest& msg);
std::pair<wifi_error, TwtStats> twtGetStats(const std::string& iface_name, uint8_t configId);
wifi_error twtClearStats(const std::string& iface_name, uint8_t configId);
wifi_error setDtimConfig(const std::string& iface_name, uint32_t multiplier);
// Retrieve the list of usable channels in the requested bands
// for the requested modes
std::pair<wifi_error, std::vector<wifi_usable_channel>> getUsableChannels(
uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask);
wifi_error triggerSubsystemRestart();
wifi_error setIndoorState(bool isIndoor);
std::pair<wifi_error, wifi_radio_combination_matrix*> getSupportedRadioCombinationsMatrix();
// CHRE NAN RTT function
wifi_error chreNanRttRequest(const std::string& iface_name, bool enable);
wifi_error chreRegisterHandler(const std::string& iface_name,
const ChreCallbackHandlers& handler);
wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable);
wifi_error getWifiCachedScanResults(const std::string& iface_name,
const CachedScanResultsCallbackHandlers& handler);
private:
// Retrieve interface handles for all the available interfaces.
wifi_error retrieveIfaceHandles();
wifi_interface_handle getIfaceHandle(const std::string& iface_name);
// Run the legacy HAL event loop thread.
void runEventLoop();
// Retrieve the cached gscan results to pass the results back to the
// external callbacks.
std::pair<wifi_error, std::vector<wifi_cached_scan_results>> getGscanCachedResults(
const std::string& iface_name);
void invalidate();
// Handles wifi (error) status of Virtual interface create/delete
wifi_error handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
wifi_error status);
// Global function table of legacy HAL.
wifi_hal_fn global_func_table_;
// Opaque handle to be used for all global operations.
wifi_handle global_handle_;
// Map of interface name to handle that is to be used for all interface
// specific operations.
std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
// Flag to indicate if we have initiated the cleanup of legacy HAL.
std::atomic<bool> awaiting_event_loop_termination_;
std::condition_variable_any stop_wait_cv_;
// Flag to indicate if the legacy HAL has been started.
bool is_started_;
std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
// Flag to indicate if this HAL is for the primary chip. This is used
// in order to avoid some hard-coded behavior used with older HALs,
// such as bring wlan0 interface up/down on start/stop HAL.
// it may be removed once vendor HALs are updated.
bool is_primary_;
};
} // namespace legacy_hal
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_LEGACY_HAL_H_

View File

@@ -0,0 +1,252 @@
/*
* 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_legacy_hal_factory.h"
#include <android-base/logging.h>
#include <dirent.h>
#include <dlfcn.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "wifi_legacy_hal_stubs.h"
namespace {
static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
static constexpr char kVendorHalsDescExt[] = ".xml";
static constexpr uint32_t kVendorHalsDescVersion = 1;
bool isDirectory(struct dirent* entryPtr) {
bool isDir = false;
if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
isDir = (entryPtr->d_type == DT_DIR);
} else {
struct stat entryStat;
stat(entryPtr->d_name, &entryStat);
isDir = S_ISDIR(entryStat.st_mode);
}
return isDir;
}
bool isFileExtension(const char* name, const char* ext) {
if (name == NULL) return false;
if (ext == NULL) return false;
size_t extLen = strlen(ext);
size_t nameLen = strlen(name);
if (extLen > nameLen) return false;
if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
return true;
}
}; // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace legacy_hal {
WifiLegacyHalFactory::WifiLegacyHalFactory(
const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool)
: iface_tool_(iface_tool) {}
std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
if (legacy_hals_.empty()) {
if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList();
for (auto& desc : descs_) {
std::shared_ptr<WifiLegacyHal> hal =
std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn, desc.primary);
legacy_hals_.push_back(hal);
}
}
return legacy_hals_;
}
bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
wifi_hal_lib_desc desc;
if (!initLinkedHalFunctionTable(&desc.fn)) return false;
desc.primary = true;
desc.handle = NULL;
descs_.push_back(desc);
return true;
}
bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
init_wifi_vendor_hal_func_table_t initfn;
initfn = (init_wifi_vendor_hal_func_table_t)dlsym(RTLD_DEFAULT,
"init_wifi_vendor_hal_func_table");
if (!initfn) {
LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
return false;
}
if (!initHalFuncTableWithStubs(hal_fn)) {
LOG(ERROR) << "Can not initialize the basic function pointer table";
return false;
}
if (initfn(hal_fn) != WIFI_SUCCESS) {
LOG(ERROR) << "Can not initialize the vendor function pointer table";
return false;
}
return true;
}
/*
* Overall structure of the HAL descriptor XML schema
*
* <?xml version="1.0" encoding="UTF-8"?>
* <WifiVendorHal version="1">
* <path>/vendor/lib64/libwifi-hal-qcom.so</path>
* <primary>1</primary>
* </WifiVendorHal>
*/
void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
xmlDocPtr xml;
xmlNodePtr node, cnode;
char* version;
std::string path;
xmlChar* value;
wifi_hal_lib_desc desc;
LOG(INFO) << "processing vendor HALs descriptions in " << kVendorHalsDescPath;
DIR* dirPtr = ::opendir(kVendorHalsDescPath);
if (dirPtr == NULL) {
LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
return;
}
for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
entryPtr = ::readdir(dirPtr)) {
if (isDirectory(entryPtr)) continue;
if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
continue; // only process .xml files
LOG(INFO) << "processing config file: " << entryPtr->d_name;
std::string fullPath(kVendorHalsDescPath);
fullPath.append("/");
fullPath.append(entryPtr->d_name);
xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
if (!xml) {
LOG(ERROR) << "failed to parse: " << entryPtr->d_name << " skipping...";
continue;
}
node = xmlDocGetRootElement(xml);
if (!node) {
LOG(ERROR) << "empty config file: " << entryPtr->d_name << " skipping...";
goto skip;
}
if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
LOG(ERROR) << "bad config, root element not WifiVendorHal: " << entryPtr->d_name
<< " skipping...";
goto skip;
}
version = (char*)xmlGetProp(node, BAD_CAST "version");
if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
LOG(ERROR) << "conf file: " << entryPtr->d_name
<< "must have version: " << kVendorHalsDescVersion << ", skipping...";
goto skip;
}
cnode = node->children;
path.clear();
desc.primary = false;
while (cnode) {
if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
value = xmlNodeListGetString(xml, cnode->children, 1);
if (value) path = (char*)value;
xmlFree(value);
} else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
value = xmlNodeListGetString(xml, cnode->children, 1);
desc.primary = !xmlStrcmp(value, BAD_CAST "1");
xmlFree(value);
}
cnode = cnode->next;
}
if (path.empty()) {
LOG(ERROR) << "hal library path not provided in: " << entryPtr->d_name
<< ", skipping...";
goto skip;
}
if (loadVendorHalLib(path, desc)) {
if (desc.primary)
descs_.insert(descs_.begin(), desc);
else
descs_.push_back(desc);
}
skip:
xmlFreeDoc(xml);
}
::closedir(dirPtr);
}
bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc) {
void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
init_wifi_vendor_hal_func_table_t initfn;
wifi_error res;
if (!h) {
LOG(ERROR) << "failed to open vendor hal library: " << path;
return false;
}
initfn = (init_wifi_vendor_hal_func_table_t)dlsym(h, "init_wifi_vendor_hal_func_table");
if (!initfn) {
LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
goto out_err;
}
if (!initHalFuncTableWithStubs(&desc.fn)) {
LOG(ERROR) << "Can not initialize the basic function pointer table";
goto out_err;
}
res = initfn(&desc.fn);
if (res != WIFI_SUCCESS) {
LOG(ERROR) << "failed to initialize the vendor func table in: " << path
<< " error: " << res;
goto out_err;
}
res = desc.fn.wifi_early_initialize();
// vendor HALs which do not implement early_initialize will return
// WIFI_ERROR_NOT_SUPPORTED, treat this as success.
if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
LOG(ERROR) << "early initialization failed in: " << path << " error: " << res;
goto out_err;
}
desc.handle = h;
return true;
out_err:
dlclose(h);
return false;
}
} // namespace legacy_hal
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,64 @@
/*
* 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.
*/
#ifndef WIFI_LEGACY_HAL_FACTORY_H_
#define WIFI_LEGACY_HAL_FACTORY_H_
#include <wifi_system/interface_tool.h>
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
// This is in a separate namespace to prevent typename conflicts between
// the legacy HAL types and the AIDL interface types.
namespace legacy_hal {
/**
* Class that creates WifiLegacyHal objects for vendor HALs in the system.
*/
class WifiLegacyHalFactory {
public:
WifiLegacyHalFactory(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool);
virtual ~WifiLegacyHalFactory() = default;
std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
private:
typedef struct {
wifi_hal_fn fn;
bool primary;
void* handle;
} wifi_hal_lib_desc;
bool initVendorHalDescriptorFromLinked();
void initVendorHalsDescriptorList();
bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
std::vector<wifi_hal_lib_desc> descs_;
std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
};
} // namespace legacy_hal
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_LEGACY_HAL_FACTORY_H_

View File

@@ -0,0 +1,177 @@
/*
* 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_legacy_hal_stubs.h"
// TODO: Remove these stubs from HalTool in libwifi-system.
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace legacy_hal {
template <typename>
struct stubFunction;
template <typename R, typename... Args>
struct stubFunction<R (*)(Args...)> {
static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
};
template <typename... Args>
struct stubFunction<void (*)(Args...)> {
static constexpr void invoke(Args...) {}
};
template <typename T>
void populateStubFor(T* val) {
*val = &stubFunction<T>::invoke;
}
bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
if (hal_fn == nullptr) {
return false;
}
populateStubFor(&hal_fn->wifi_initialize);
populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
populateStubFor(&hal_fn->wifi_cleanup);
populateStubFor(&hal_fn->wifi_event_loop);
populateStubFor(&hal_fn->wifi_get_error_info);
populateStubFor(&hal_fn->wifi_get_supported_feature_set);
populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
populateStubFor(&hal_fn->wifi_get_supported_channels);
populateStubFor(&hal_fn->wifi_is_epr_supported);
populateStubFor(&hal_fn->wifi_get_ifaces);
populateStubFor(&hal_fn->wifi_get_iface_name);
populateStubFor(&hal_fn->wifi_set_iface_event_handler);
populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
populateStubFor(&hal_fn->wifi_start_gscan);
populateStubFor(&hal_fn->wifi_stop_gscan);
populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
populateStubFor(&hal_fn->wifi_set_significant_change_handler);
populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
populateStubFor(&hal_fn->wifi_set_link_stats);
populateStubFor(&hal_fn->wifi_get_link_stats);
populateStubFor(&hal_fn->wifi_clear_link_stats);
populateStubFor(&hal_fn->wifi_get_valid_channels);
populateStubFor(&hal_fn->wifi_rtt_range_request);
populateStubFor(&hal_fn->wifi_rtt_range_cancel);
populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
populateStubFor(&hal_fn->wifi_enable_responder);
populateStubFor(&hal_fn->wifi_disable_responder);
populateStubFor(&hal_fn->wifi_set_nodfs_flag);
populateStubFor(&hal_fn->wifi_start_logging);
populateStubFor(&hal_fn->wifi_set_epno_list);
populateStubFor(&hal_fn->wifi_reset_epno_list);
populateStubFor(&hal_fn->wifi_set_country_code);
populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
populateStubFor(&hal_fn->wifi_set_log_handler);
populateStubFor(&hal_fn->wifi_reset_log_handler);
populateStubFor(&hal_fn->wifi_set_alert_handler);
populateStubFor(&hal_fn->wifi_reset_alert_handler);
populateStubFor(&hal_fn->wifi_get_firmware_version);
populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
populateStubFor(&hal_fn->wifi_get_ring_data);
populateStubFor(&hal_fn->wifi_enable_tdls);
populateStubFor(&hal_fn->wifi_disable_tdls);
populateStubFor(&hal_fn->wifi_get_tdls_status);
populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
populateStubFor(&hal_fn->wifi_get_driver_version);
populateStubFor(&hal_fn->wifi_set_passpoint_list);
populateStubFor(&hal_fn->wifi_reset_passpoint_list);
populateStubFor(&hal_fn->wifi_set_lci);
populateStubFor(&hal_fn->wifi_set_lcr);
populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
populateStubFor(&hal_fn->wifi_configure_nd_offload);
populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
populateStubFor(&hal_fn->wifi_nan_enable_request);
populateStubFor(&hal_fn->wifi_nan_disable_request);
populateStubFor(&hal_fn->wifi_nan_publish_request);
populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
populateStubFor(&hal_fn->wifi_nan_subscribe_request);
populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
populateStubFor(&hal_fn->wifi_nan_stats_request);
populateStubFor(&hal_fn->wifi_nan_config_request);
populateStubFor(&hal_fn->wifi_nan_tca_request);
populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
populateStubFor(&hal_fn->wifi_nan_register_handler);
populateStubFor(&hal_fn->wifi_nan_get_version);
populateStubFor(&hal_fn->wifi_nan_get_capabilities);
populateStubFor(&hal_fn->wifi_nan_data_interface_create);
populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
populateStubFor(&hal_fn->wifi_nan_data_indication_response);
populateStubFor(&hal_fn->wifi_nan_data_end);
populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
populateStubFor(&hal_fn->wifi_set_packet_filter);
populateStubFor(&hal_fn->wifi_read_packet_filter);
populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
populateStubFor(&hal_fn->wifi_configure_roaming);
populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
populateStubFor(&hal_fn->wifi_set_latency_mode);
populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
populateStubFor(&hal_fn->wifi_virtual_interface_create);
populateStubFor(&hal_fn->wifi_virtual_interface_delete);
populateStubFor(&hal_fn->wifi_map_dscp_access_category);
populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
populateStubFor(&hal_fn->wifi_get_supported_iface_name);
populateStubFor(&hal_fn->wifi_early_initialize);
populateStubFor(&hal_fn->wifi_get_chip_feature_set);
populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels);
populateStubFor(&hal_fn->wifi_set_voip_mode);
populateStubFor(&hal_fn->wifi_twt_register_handler);
populateStubFor(&hal_fn->wifi_twt_get_capability);
populateStubFor(&hal_fn->wifi_twt_setup_request);
populateStubFor(&hal_fn->wifi_twt_teardown_request);
populateStubFor(&hal_fn->wifi_twt_info_frame_request);
populateStubFor(&hal_fn->wifi_twt_get_stats);
populateStubFor(&hal_fn->wifi_twt_clear_stats);
populateStubFor(&hal_fn->wifi_set_dtim_config);
populateStubFor(&hal_fn->wifi_get_usable_channels);
populateStubFor(&hal_fn->wifi_trigger_subsystem_restart);
populateStubFor(&hal_fn->wifi_set_indoor_state);
populateStubFor(&hal_fn->wifi_get_supported_radio_combinations_matrix);
populateStubFor(&hal_fn->wifi_nan_rtt_chre_enable_request);
populateStubFor(&hal_fn->wifi_nan_rtt_chre_disable_request);
populateStubFor(&hal_fn->wifi_chre_register_handler);
populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
populateStubFor(&hal_fn->wifi_get_cached_scan_results);
return true;
}
} // namespace legacy_hal
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,35 @@
/*
* 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.
*/
#ifndef WIFI_LEGACY_HAL_STUBS_H_
#define WIFI_LEGACY_HAL_STUBS_H_
#include <hardware_legacy/wifi_hal.h>
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace legacy_hal {
bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
} // namespace legacy_hal
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_LEGACY_HAL_STUBS_H_

View File

@@ -0,0 +1,88 @@
/*
* 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_mode_controller.h"
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <private/android_filesystem_config.h>
namespace {
using aidl::android::hardware::wifi::IfaceType;
using android::wifi_hal::DriverTool;
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_IFACE:
// NAN is exposed in STA mode currently.
mode = DriverTool::kFirmwareModeSta;
break;
case IfaceType::STA:
mode = DriverTool::kFirmwareModeSta;
break;
}
return mode;
}
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace mode_controller {
WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
return driver_tool_->IsFirmwareModeChangeNeeded(convertIfaceTypeToFirmwareMode(type));
}
bool WifiModeController::initialize() {
if (!driver_tool_->LoadDriver()) {
LOG(ERROR) << "Failed to load WiFi driver";
return false;
}
return true;
}
bool WifiModeController::changeFirmwareMode(IfaceType type) {
if (!driver_tool_->ChangeFirmwareMode(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 wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,59 @@
/*
* 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.
*/
#ifndef WIFI_MODE_CONTROLLER_H_
#define WIFI_MODE_CONTROLLER_H_
#include <aidl/android/hardware/wifi/IWifi.h>
#include <wifi_hal/driver_tool.h>
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
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();
virtual ~WifiModeController() = default;
// Checks if a firmware mode change is necessary to support the specified
// iface type operations.
virtual bool isFirmwareModeChangeNeeded(IfaceType type);
virtual bool initialize();
// Change the firmware mode to support the specified iface type operations.
virtual bool changeFirmwareMode(IfaceType type);
// Unload the driver. This should be invoked whenever |IWifi.stop()| is
// invoked.
virtual bool deinitialize();
private:
std::unique_ptr<::android::wifi_hal::DriverTool> driver_tool_;
};
} // namespace mode_controller
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_MODE_CONTROLLER_H_

View File

@@ -0,0 +1,751 @@
/*
* 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_nan_iface.h"
#include <android-base/logging.h>
#include "aidl_return_util.h"
#include "aidl_struct_util.h"
#include "wifi_status_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using aidl_return_util::validateAndCall;
WifiNanIface::WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: ifname_(ifname),
is_dedicated_iface_(is_dedicated_iface),
legacy_hal_(legacy_hal),
iface_util_(iface_util),
is_valid_(true) {}
std::shared_ptr<WifiNanIface> WifiNanIface::create(
const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util) {
std::shared_ptr<WifiNanIface> ptr = ndk::SharedRefBase::make<WifiNanIface>(
ifname, is_dedicated_iface, legacy_hal, iface_util);
if (is_dedicated_iface) {
// If using a dedicated iface, set the iface up first.
if (!iface_util.lock()->setUpState(ifname, true)) {
// Fatal failure, invalidate the iface object.
ptr->invalidate();
return nullptr;
}
}
std::weak_ptr<WifiNanIface> weak_ptr_this(ptr);
ptr->setWeakPtr(weak_ptr_this);
ptr->registerCallbackHandlers();
return ptr;
}
void WifiNanIface::registerCallbackHandlers() {
// Register all the callbacks here. These should be valid for the lifetime
// of the object. Whenever the mode changes legacy HAL will remove
// all of these callbacks.
legacy_hal::NanCallbackHandlers callback_handlers;
std::weak_ptr<WifiNanIface> weak_ptr_this = weak_ptr_this_;
// Callback for response.
callback_handlers.on_notify_response = [weak_ptr_this](legacy_hal::transaction_id id,
const legacy_hal::NanResponseMsg& msg) {
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;
}
NanStatus nanStatus;
if (!aidl_struct_util::convertLegacyNanResponseHeaderToAidl(msg, &nanStatus)) {
LOG(ERROR) << "Failed to convert nan response header";
return;
}
switch (msg.response_type) {
case legacy_hal::NAN_RESPONSE_ENABLED: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyEnableResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_DISABLED: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyDisableResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_PUBLISH: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyStartPublishResponse(id, nanStatus,
msg.body.publish_response.publish_id)
.isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyStopPublishResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyTransmitFollowupResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyStartSubscribeResponse(
id, nanStatus, msg.body.subscribe_response.subscribe_id)
.isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyStopSubscribeResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_CONFIG: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyConfigResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_GET_CAPABILITIES: {
NanCapabilities aidl_struct;
if (!aidl_struct_util::convertLegacyNanCapabilitiesResponseToAidl(
msg.body.nan_capabilities, &aidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyCapabilitiesResponse(id, nanStatus, aidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_DP_INTERFACE_CREATE: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyCreateDataInterfaceResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_DP_INTERFACE_DELETE: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyDeleteDataInterfaceResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyInitiateDataPathResponse(
id, nanStatus,
msg.body.data_request_response.ndp_instance_id)
.isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyRespondToDataPathIndicationResponse(id, nanStatus)
.isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_DP_END: {
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->notifyTerminateDataPathResponse(id, nanStatus).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
break;
}
case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
/* fall through */
case legacy_hal::NAN_RESPONSE_TCA:
/* fall through */
case legacy_hal::NAN_RESPONSE_STATS:
/* fall through */
case legacy_hal::NAN_RESPONSE_ERROR:
/* fall through */
default:
LOG(ERROR) << "Unknown or unhandled response type: " << msg.response_type;
return;
}
};
callback_handlers.on_event_disc_eng_event = [weak_ptr_this](
const legacy_hal::NanDiscEngEventInd& msg) {
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;
}
NanClusterEventInd aidl_struct;
// event types defined identically - hence can be cast
aidl_struct.eventType = (NanClusterEventType)msg.event_type;
aidl_struct.addr = std::array<uint8_t, 6>();
std::copy(msg.data.mac_addr.addr, msg.data.mac_addr.addr + 6, std::begin(aidl_struct.addr));
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventClusterEvent(aidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_disabled = [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
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;
}
NanStatus status;
aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
&status);
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventDisabled(status).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_publish_terminated =
[weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
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;
}
NanStatus status;
aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason,
sizeof(msg.nan_reason), &status);
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventPublishTerminated(msg.publish_id, status).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_subscribe_terminated =
[weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
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;
}
NanStatus status;
aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason,
sizeof(msg.nan_reason), &status);
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventSubscribeTerminated(msg.subscribe_id, status).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_match = [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
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;
}
NanMatchInd aidl_struct;
if (!aidl_struct_util::convertLegacyNanMatchIndToAidl(msg, &aidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventMatch(aidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_match_expired = [weak_ptr_this](
const legacy_hal::NanMatchExpiredInd& msg) {
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->eventMatchExpired(msg.publish_subscribe_id, msg.requestor_instance_id)
.isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_followup = [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
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;
}
NanFollowupReceivedInd aidl_struct;
if (!aidl_struct_util::convertLegacyNanFollowupIndToAidl(msg, &aidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventFollowupReceived(aidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_transmit_follow_up =
[weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
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;
}
NanStatus status;
aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason,
sizeof(msg.nan_reason), &status);
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_data_path_request =
[weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
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;
}
NanDataPathRequestInd aidl_struct;
if (!aidl_struct_util::convertLegacyNanDataPathRequestIndToAidl(msg,
&aidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventDataPathRequest(aidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_data_path_confirm =
[weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
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;
}
NanDataPathConfirmInd aidl_struct;
if (!aidl_struct_util::convertLegacyNanDataPathConfirmIndToAidl(msg,
&aidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventDataPathConfirm(aidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
callback_handlers.on_event_data_path_end =
[weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
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()) {
for (int i = 0; i < msg.num_ndp_instances; ++i) {
if (!callback->eventDataPathTerminated(msg.ndp_instance_id[i]).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
}
};
callback_handlers.on_event_beacon_sdf_payload =
[](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
};
callback_handlers.on_event_range_request = [](const legacy_hal::NanRangeRequestInd& /* msg */) {
LOG(ERROR) << "on_event_range_request - should not be called";
};
callback_handlers.on_event_range_report = [](const legacy_hal::NanRangeReportInd& /* msg */) {
LOG(ERROR) << "on_event_range_report - should not be called";
};
callback_handlers.on_event_schedule_update =
[weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& msg) {
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;
}
NanDataPathScheduleUpdateInd aidl_struct;
if (!aidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToAidl(
msg, &aidl_struct)) {
LOG(ERROR) << "Failed to convert nan capabilities response";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventDataPathScheduleUpdate(aidl_struct).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_, callback_handlers);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
invalidate();
}
// Register for iface state toggle events.
iface_util::IfaceEventHandlers event_handlers = {};
event_handlers.on_state_toggle_off_on = [weak_ptr_this](const std::string& /* iface_name */) {
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;
}
// Tell framework that NAN has been disabled.
NanStatus status = {NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->eventDisabled(status).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
}
void WifiNanIface::setWeakPtr(std::weak_ptr<WifiNanIface> ptr) {
weak_ptr_this_ = ptr;
}
void WifiNanIface::invalidate() {
if (!isValid()) {
return;
}
// send commands to HAL to actually disable and destroy interfaces
legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
legacy_hal_.reset();
event_cb_handler_.invalidate();
is_valid_ = false;
if (is_dedicated_iface_) {
// If using a dedicated iface, set the iface down.
iface_util_.lock()->setUpState(ifname_, false);
}
}
bool WifiNanIface::isValid() {
return is_valid_;
}
std::string WifiNanIface::getName() {
return ifname_;
}
std::set<std::shared_ptr<IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks() {
LOG(ERROR) << "Using original getEventCallbacks";
return event_cb_handler_.getCallbacks();
}
ndk::ScopedAStatus WifiNanIface::getName(std::string* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::getNameInternal, _aidl_return);
}
ndk::ScopedAStatus WifiNanIface::registerEventCallback(
const std::shared_ptr<IWifiNanIfaceEventCallback>& callback) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::registerEventCallbackInternal, callback);
}
ndk::ScopedAStatus WifiNanIface::getCapabilitiesRequest(char16_t in_cmdId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::getCapabilitiesRequestInternal, in_cmdId);
}
ndk::ScopedAStatus WifiNanIface::enableRequest(char16_t in_cmdId, const NanEnableRequest& in_msg1,
const NanConfigRequestSupplemental& in_msg2) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::enableRequestInternal, in_cmdId, in_msg1, in_msg2);
}
ndk::ScopedAStatus WifiNanIface::configRequest(char16_t in_cmdId, const NanConfigRequest& in_msg1,
const NanConfigRequestSupplemental& in_msg2) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::configRequestInternal, in_cmdId, in_msg1, in_msg2);
}
ndk::ScopedAStatus WifiNanIface::disableRequest(char16_t in_cmdId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::disableRequestInternal, in_cmdId);
}
ndk::ScopedAStatus WifiNanIface::startPublishRequest(char16_t in_cmdId,
const NanPublishRequest& in_msg) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::startPublishRequestInternal, in_cmdId, in_msg);
}
ndk::ScopedAStatus WifiNanIface::stopPublishRequest(char16_t in_cmdId, int8_t in_sessionId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::stopPublishRequestInternal, in_cmdId, in_sessionId);
}
ndk::ScopedAStatus WifiNanIface::startSubscribeRequest(char16_t in_cmdId,
const NanSubscribeRequest& in_msg) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::startSubscribeRequestInternal, in_cmdId, in_msg);
}
ndk::ScopedAStatus WifiNanIface::stopSubscribeRequest(char16_t in_cmdId, int8_t in_sessionId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::stopSubscribeRequestInternal, in_cmdId, in_sessionId);
}
ndk::ScopedAStatus WifiNanIface::transmitFollowupRequest(char16_t in_cmdId,
const NanTransmitFollowupRequest& in_msg) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::transmitFollowupRequestInternal, in_cmdId, in_msg);
}
ndk::ScopedAStatus WifiNanIface::createDataInterfaceRequest(char16_t in_cmdId,
const std::string& in_ifaceName) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::createDataInterfaceRequestInternal, in_cmdId,
in_ifaceName);
}
ndk::ScopedAStatus WifiNanIface::deleteDataInterfaceRequest(char16_t in_cmdId,
const std::string& in_ifaceName) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::deleteDataInterfaceRequestInternal, in_cmdId,
in_ifaceName);
}
ndk::ScopedAStatus WifiNanIface::initiateDataPathRequest(char16_t in_cmdId,
const NanInitiateDataPathRequest& in_msg) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::initiateDataPathRequestInternal, in_cmdId, in_msg);
}
ndk::ScopedAStatus WifiNanIface::respondToDataPathIndicationRequest(
char16_t in_cmdId, const NanRespondToDataPathIndicationRequest& in_msg) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::respondToDataPathIndicationRequestInternal, in_cmdId,
in_msg);
}
ndk::ScopedAStatus WifiNanIface::terminateDataPathRequest(char16_t in_cmdId,
int32_t in_ndpInstanceId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiNanIface::terminateDataPathRequestInternal, in_cmdId,
in_ndpInstanceId);
}
std::pair<std::string, ndk::ScopedAStatus> WifiNanIface::getNameInternal() {
return {ifname_, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiNanIface::registerEventCallbackInternal(
const std::shared_ptr<IWifiNanIfaceEventCallback>& callback) {
if (!event_cb_handler_.addCallback(callback)) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus WifiNanIface::getCapabilitiesRequestInternal(char16_t cmd_id) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::enableRequestInternal(char16_t cmd_id,
const NanEnableRequest& msg1,
const NanConfigRequestSupplemental& msg2) {
legacy_hal::NanEnableRequest legacy_msg;
if (!aidl_struct_util::convertAidlNanEnableRequestToLegacy(msg1, msg2, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::configRequestInternal(char16_t cmd_id,
const NanConfigRequest& msg1,
const NanConfigRequestSupplemental& msg2) {
legacy_hal::NanConfigRequest legacy_msg;
if (!aidl_struct_util::convertAidlNanConfigRequestToLegacy(msg1, msg2, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::disableRequestInternal(char16_t cmd_id) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::startPublishRequestInternal(char16_t cmd_id,
const NanPublishRequest& msg) {
legacy_hal::NanPublishRequest legacy_msg;
if (!aidl_struct_util::convertAidlNanPublishRequestToLegacy(msg, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::stopPublishRequestInternal(char16_t cmd_id, int8_t sessionId) {
legacy_hal::NanPublishCancelRequest legacy_msg;
legacy_msg.publish_id = sessionId;
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::startSubscribeRequestInternal(char16_t cmd_id,
const NanSubscribeRequest& msg) {
legacy_hal::NanSubscribeRequest legacy_msg;
if (!aidl_struct_util::convertAidlNanSubscribeRequestToLegacy(msg, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::stopSubscribeRequestInternal(char16_t cmd_id, int8_t sessionId) {
legacy_hal::NanSubscribeCancelRequest legacy_msg;
legacy_msg.subscribe_id = sessionId;
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::transmitFollowupRequestInternal(
char16_t cmd_id, const NanTransmitFollowupRequest& msg) {
legacy_hal::NanTransmitFollowupRequest legacy_msg;
if (!aidl_struct_util::convertAidlNanTransmitFollowupRequestToLegacy(msg, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::createDataInterfaceRequestInternal(char16_t cmd_id,
const std::string& iface_name) {
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::deleteDataInterfaceRequestInternal(char16_t cmd_id,
const std::string& iface_name) {
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::initiateDataPathRequestInternal(
char16_t cmd_id, const NanInitiateDataPathRequest& msg) {
legacy_hal::NanDataPathInitiatorRequest legacy_msg;
if (!aidl_struct_util::convertAidlNanDataPathInitiatorRequestToLegacy(msg, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
char16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
legacy_hal::NanDataPathIndicationResponse legacy_msg;
if (!aidl_struct_util::convertAidlNanDataPathIndicationResponseToLegacy(msg, &legacy_msg)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id, legacy_msg);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiNanIface::terminateDataPathRequestInternal(char16_t cmd_id,
int32_t ndpInstanceId) {
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
return createWifiStatusFromLegacyError(legacy_status);
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,134 @@
/*
* 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.
*/
#ifndef WIFI_NAN_IFACE_H_
#define WIFI_NAN_IFACE_H_
#include <aidl/android/hardware/wifi/BnWifiNanIface.h>
#include <aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.h>
#include <android-base/macros.h>
#include "aidl_callback_util.h"
#include "wifi_iface_util.h"
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* AIDL interface object used to control a NAN Iface instance.
*/
class WifiNanIface : public BnWifiNanIface {
public:
WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Factory method - use instead of default constructor.
static std::shared_ptr<WifiNanIface> create(
const std::string& ifname, bool is_dedicated_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
std::string getName();
// AIDL methods exposed.
ndk::ScopedAStatus getName(std::string* _aidl_return) override;
ndk::ScopedAStatus registerEventCallback(
const std::shared_ptr<IWifiNanIfaceEventCallback>& in_callback) override;
ndk::ScopedAStatus getCapabilitiesRequest(char16_t in_cmdId) override;
ndk::ScopedAStatus enableRequest(char16_t in_cmdId, const NanEnableRequest& in_msg1,
const NanConfigRequestSupplemental& in_msg2) override;
ndk::ScopedAStatus configRequest(char16_t in_cmdId, const NanConfigRequest& in_msg1,
const NanConfigRequestSupplemental& in_msg2) override;
ndk::ScopedAStatus disableRequest(char16_t in_cmdId) override;
ndk::ScopedAStatus startPublishRequest(char16_t in_cmdId,
const NanPublishRequest& in_msg) override;
ndk::ScopedAStatus stopPublishRequest(char16_t in_cmdId, int8_t in_sessionId) override;
ndk::ScopedAStatus startSubscribeRequest(char16_t in_cmdId,
const NanSubscribeRequest& in_msg) override;
ndk::ScopedAStatus stopSubscribeRequest(char16_t in_cmdId, int8_t in_sessionId) override;
ndk::ScopedAStatus transmitFollowupRequest(char16_t in_cmdId,
const NanTransmitFollowupRequest& in_msg) override;
ndk::ScopedAStatus createDataInterfaceRequest(char16_t in_cmdId,
const std::string& in_ifaceName) override;
ndk::ScopedAStatus deleteDataInterfaceRequest(char16_t in_cmdId,
const std::string& in_ifaceName) override;
ndk::ScopedAStatus initiateDataPathRequest(char16_t in_cmdId,
const NanInitiateDataPathRequest& in_msg) override;
ndk::ScopedAStatus respondToDataPathIndicationRequest(
char16_t in_cmdId, const NanRespondToDataPathIndicationRequest& in_msg) override;
ndk::ScopedAStatus terminateDataPathRequest(char16_t in_cmdId,
int32_t in_ndpInstanceId) override;
protected:
// Accessible to child class in the gTest suite.
void setWeakPtr(std::weak_ptr<WifiNanIface> ptr);
void registerCallbackHandlers();
private:
// Corresponding worker functions for the AIDL methods.
std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
ndk::ScopedAStatus registerEventCallbackInternal(
const std::shared_ptr<IWifiNanIfaceEventCallback>& callback);
ndk::ScopedAStatus getCapabilitiesRequestInternal(char16_t cmd_id);
ndk::ScopedAStatus enableRequestInternal(char16_t cmd_id, const NanEnableRequest& msg1,
const NanConfigRequestSupplemental& msg2);
ndk::ScopedAStatus configRequestInternal(char16_t cmd_id, const NanConfigRequest& msg1,
const NanConfigRequestSupplemental& msg2);
ndk::ScopedAStatus disableRequestInternal(char16_t cmd_id);
ndk::ScopedAStatus startPublishRequestInternal(char16_t cmd_id, const NanPublishRequest& msg);
ndk::ScopedAStatus stopPublishRequestInternal(char16_t cmd_id, int8_t sessionId);
ndk::ScopedAStatus startSubscribeRequestInternal(char16_t cmd_id,
const NanSubscribeRequest& msg);
ndk::ScopedAStatus stopSubscribeRequestInternal(char16_t cmd_id, int8_t sessionId);
ndk::ScopedAStatus transmitFollowupRequestInternal(char16_t cmd_id,
const NanTransmitFollowupRequest& msg);
ndk::ScopedAStatus createDataInterfaceRequestInternal(char16_t cmd_id,
const std::string& iface_name);
ndk::ScopedAStatus deleteDataInterfaceRequestInternal(char16_t cmd_id,
const std::string& iface_name);
ndk::ScopedAStatus initiateDataPathRequestInternal(char16_t cmd_id,
const NanInitiateDataPathRequest& msg);
ndk::ScopedAStatus respondToDataPathIndicationRequestInternal(
char16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
ndk::ScopedAStatus terminateDataPathRequestInternal(char16_t cmd_id, int32_t ndpInstanceId);
// Overridden in the gTest suite.
virtual std::set<std::shared_ptr<IWifiNanIfaceEventCallback>> getEventCallbacks();
std::string ifname_;
bool is_dedicated_iface_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
bool is_valid_;
std::weak_ptr<WifiNanIface> weak_ptr_this_;
aidl_callback_util::AidlCallbackHandler<IWifiNanIfaceEventCallback> event_cb_handler_;
DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_NAN_IFACE_H_

View File

@@ -0,0 +1,59 @@
/*
* 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_p2p_iface.h"
#include <android-base/logging.h>
#include "aidl_return_util.h"
#include "wifi_status_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using aidl_return_util::validateAndCall;
WifiP2pIface::WifiP2pIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
: ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
void WifiP2pIface::invalidate() {
legacy_hal_.reset();
is_valid_ = false;
}
bool WifiP2pIface::isValid() {
return is_valid_;
}
std::string WifiP2pIface::getName() {
return ifname_;
}
ndk::ScopedAStatus WifiP2pIface::getName(std::string* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiP2pIface::getNameInternal, _aidl_return);
}
std::pair<std::string, ndk::ScopedAStatus> WifiP2pIface::getNameInternal() {
return {ifname_, ndk::ScopedAStatus::ok()};
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,61 @@
/*
* 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.
*/
#ifndef WIFI_P2P_IFACE_H_
#define WIFI_P2P_IFACE_H_
#include <aidl/android/hardware/wifi/BnWifiP2pIface.h>
#include <android-base/macros.h>
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* AIDL interface object used to control a P2P Iface instance.
*/
class WifiP2pIface : public BnWifiP2pIface {
public:
WifiP2pIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
std::string getName();
// AIDL methods exposed.
ndk::ScopedAStatus getName(std::string* _aidl_return) override;
private:
// Corresponding worker functions for the AIDL methods.
std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
std::string ifname_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_P2P_IFACE_H_

View File

@@ -0,0 +1,255 @@
/*
* 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_rtt_controller.h"
#include <android-base/logging.h>
#include "aidl_return_util.h"
#include "aidl_struct_util.h"
#include "wifi_status_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using aidl_return_util::validateAndCall;
WifiRttController::WifiRttController(const std::string& iface_name,
const std::shared_ptr<IWifiStaIface>& bound_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
: ifname_(iface_name), bound_iface_(bound_iface), legacy_hal_(legacy_hal), is_valid_(true) {}
std::shared_ptr<WifiRttController> WifiRttController::create(
const std::string& iface_name, const std::shared_ptr<IWifiStaIface>& bound_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal) {
std::shared_ptr<WifiRttController> ptr =
ndk::SharedRefBase::make<WifiRttController>(iface_name, bound_iface, legacy_hal);
std::weak_ptr<WifiRttController> weak_ptr_this(ptr);
ptr->setWeakPtr(weak_ptr_this);
return ptr;
}
void WifiRttController::invalidate() {
legacy_hal_.reset();
event_callbacks_.clear();
is_valid_ = false;
};
bool WifiRttController::isValid() {
return is_valid_;
}
void WifiRttController::setWeakPtr(std::weak_ptr<WifiRttController> ptr) {
weak_ptr_this_ = ptr;
}
std::vector<std::shared_ptr<IWifiRttControllerEventCallback>>
WifiRttController::getEventCallbacks() {
return event_callbacks_;
}
std::string WifiRttController::getIfaceName() {
return ifname_;
}
ndk::ScopedAStatus WifiRttController::getBoundIface(std::shared_ptr<IWifiStaIface>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::getBoundIfaceInternal, _aidl_return);
}
ndk::ScopedAStatus WifiRttController::registerEventCallback(
const std::shared_ptr<IWifiRttControllerEventCallback>& callback) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::registerEventCallbackInternal, callback);
}
ndk::ScopedAStatus WifiRttController::rangeRequest(int32_t in_cmdId,
const std::vector<RttConfig>& in_rttConfigs) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::rangeRequestInternal, in_cmdId, in_rttConfigs);
}
ndk::ScopedAStatus WifiRttController::rangeCancel(int32_t in_cmdId,
const std::vector<MacAddress>& in_addrs) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::rangeCancelInternal, in_cmdId, in_addrs);
}
ndk::ScopedAStatus WifiRttController::getCapabilities(RttCapabilities* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::getCapabilitiesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiRttController::setLci(int32_t in_cmdId, const RttLciInformation& in_lci) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::setLciInternal, in_cmdId, in_lci);
}
ndk::ScopedAStatus WifiRttController::setLcr(int32_t in_cmdId, const RttLcrInformation& in_lcr) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::setLcrInternal, in_cmdId, in_lcr);
}
ndk::ScopedAStatus WifiRttController::getResponderInfo(RttResponder* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::getResponderInfoInternal, _aidl_return);
}
ndk::ScopedAStatus WifiRttController::enableResponder(int32_t in_cmdId,
const WifiChannelInfo& in_channelHint,
int32_t in_maxDurationInSeconds,
const RttResponder& in_info) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::enableResponderInternal, in_cmdId, in_channelHint,
in_maxDurationInSeconds, in_info);
}
ndk::ScopedAStatus WifiRttController::disableResponder(int32_t in_cmdId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
&WifiRttController::disableResponderInternal, in_cmdId);
}
std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus>
WifiRttController::getBoundIfaceInternal() {
return {bound_iface_, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiRttController::registerEventCallbackInternal(
const std::shared_ptr<IWifiRttControllerEventCallback>& callback) {
event_callbacks_.emplace_back(callback);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus WifiRttController::rangeRequestInternal(
int32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
if (!aidl_struct_util::convertAidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
std::weak_ptr<WifiRttController> weak_ptr_this = weak_ptr_this_;
const auto& on_results_callback =
[weak_ptr_this](legacy_hal::wifi_request_id id,
const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
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<RttResult> aidl_results;
if (!aidl_struct_util::convertLegacyVectorOfRttResultToAidl(results,
&aidl_results)) {
LOG(ERROR) << "Failed to convert rtt results to AIDL structs";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->onResults(id, aidl_results).isOk()) {
LOG(ERROR) << "Failed to invoke the callback";
}
}
};
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
ifname_, cmd_id, legacy_configs, on_results_callback);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiRttController::rangeCancelInternal(int32_t cmd_id,
const std::vector<MacAddress>& addrs) {
std::vector<std::array<uint8_t, ETH_ALEN>> legacy_addrs;
for (const auto& addr : addrs) {
std::array<uint8_t, ETH_ALEN> addr_array;
std::copy_n(addr.data.begin(), ETH_ALEN, addr_array.begin());
legacy_addrs.push_back(addr_array);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id, legacy_addrs);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<RttCapabilities, ndk::ScopedAStatus> WifiRttController::getCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_rtt_capabilities legacy_caps;
std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {RttCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
}
RttCapabilities aidl_caps;
if (!aidl_struct_util::convertLegacyRttCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
return {RttCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_caps, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiRttController::setLciInternal(int32_t cmd_id, const RttLciInformation& lci) {
legacy_hal::wifi_lci_information legacy_lci;
if (!aidl_struct_util::convertAidlRttLciInformationToLegacy(lci, &legacy_lci)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiRttController::setLcrInternal(int32_t cmd_id, const RttLcrInformation& lcr) {
legacy_hal::wifi_lcr_information legacy_lcr;
if (!aidl_struct_util::convertAidlRttLcrInformationToLegacy(lcr, &legacy_lcr)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<RttResponder, ndk::ScopedAStatus> WifiRttController::getResponderInfoInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_rtt_responder legacy_responder;
std::tie(legacy_status, legacy_responder) = legacy_hal_.lock()->getRttResponderInfo(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {RttResponder{}, createWifiStatusFromLegacyError(legacy_status)};
}
RttResponder aidl_responder;
if (!aidl_struct_util::convertLegacyRttResponderToAidl(legacy_responder, &aidl_responder)) {
return {RttResponder{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_responder, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiRttController::enableResponderInternal(int32_t cmd_id,
const WifiChannelInfo& channel_hint,
int32_t max_duration_seconds,
const RttResponder& info) {
legacy_hal::wifi_channel_info legacy_channel_info;
if (!aidl_struct_util::convertAidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_rtt_responder legacy_responder;
if (!aidl_struct_util::convertAidlRttResponderToLegacy(info, &legacy_responder)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder(
ifname_, cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiRttController::disableResponderInternal(int32_t cmd_id) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
return createWifiStatusFromLegacyError(legacy_status);
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,102 @@
/*
* 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.
*/
#ifndef WIFI_RTT_CONTROLLER_H_
#define WIFI_RTT_CONTROLLER_H_
#include <aidl/android/hardware/wifi/BnWifiRttController.h>
#include <aidl/android/hardware/wifi/IWifiRttControllerEventCallback.h>
#include <aidl/android/hardware/wifi/IWifiStaIface.h>
#include <android-base/macros.h>
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* AIDL interface object used to control all RTT operations.
*/
class WifiRttController : public BnWifiRttController {
public:
WifiRttController(const std::string& iface_name,
const std::shared_ptr<IWifiStaIface>& bound_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
// Factory method - use instead of default constructor.
static std::shared_ptr<WifiRttController> create(
const std::string& iface_name, const std::shared_ptr<IWifiStaIface>& bound_iface,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
std::vector<std::shared_ptr<IWifiRttControllerEventCallback>> getEventCallbacks();
std::string getIfaceName();
// AIDL methods exposed.
ndk::ScopedAStatus getBoundIface(std::shared_ptr<IWifiStaIface>* _aidl_return) override;
ndk::ScopedAStatus registerEventCallback(
const std::shared_ptr<IWifiRttControllerEventCallback>& callback) override;
ndk::ScopedAStatus rangeRequest(int32_t in_cmdId,
const std::vector<RttConfig>& in_rttConfigs) override;
ndk::ScopedAStatus rangeCancel(int32_t in_cmdId,
const std::vector<MacAddress>& in_addrs) override;
ndk::ScopedAStatus getCapabilities(RttCapabilities* _aidl_return) override;
ndk::ScopedAStatus setLci(int32_t in_cmdId, const RttLciInformation& in_lci) override;
ndk::ScopedAStatus setLcr(int32_t in_cmdId, const RttLcrInformation& in_lcr) override;
ndk::ScopedAStatus getResponderInfo(RttResponder* _aidl_return) override;
ndk::ScopedAStatus enableResponder(int32_t in_cmdId, const WifiChannelInfo& in_channelHint,
int32_t in_maxDurationInSeconds,
const RttResponder& in_info) override;
ndk::ScopedAStatus disableResponder(int32_t in_cmdId) override;
private:
// Corresponding worker functions for the AIDL methods.
std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> getBoundIfaceInternal();
ndk::ScopedAStatus registerEventCallbackInternal(
const std::shared_ptr<IWifiRttControllerEventCallback>& callback);
ndk::ScopedAStatus rangeRequestInternal(int32_t cmd_id,
const std::vector<RttConfig>& rtt_configs);
ndk::ScopedAStatus rangeCancelInternal(int32_t cmd_id, const std::vector<MacAddress>& addrs);
std::pair<RttCapabilities, ndk::ScopedAStatus> getCapabilitiesInternal();
ndk::ScopedAStatus setLciInternal(int32_t cmd_id, const RttLciInformation& lci);
ndk::ScopedAStatus setLcrInternal(int32_t cmd_id, const RttLcrInformation& lcr);
std::pair<RttResponder, ndk::ScopedAStatus> getResponderInfoInternal();
ndk::ScopedAStatus enableResponderInternal(int32_t cmd_id, const WifiChannelInfo& channel_hint,
int32_t max_duration_seconds,
const RttResponder& info);
ndk::ScopedAStatus disableResponderInternal(int32_t cmd_id);
void setWeakPtr(std::weak_ptr<WifiRttController> ptr);
std::string ifname_;
std::shared_ptr<IWifiStaIface> bound_iface_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::vector<std::shared_ptr<IWifiRttControllerEventCallback>> event_callbacks_;
std::weak_ptr<WifiRttController> weak_ptr_this_;
bool is_valid_;
DISALLOW_COPY_AND_ASSIGN(WifiRttController);
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_RTT_CONTROLLER_H_

View File

@@ -0,0 +1,558 @@
/*
* 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_sta_iface.h"
#include <android-base/logging.h>
#include "aidl_return_util.h"
#include "aidl_struct_util.h"
#include "wifi_status_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using aidl_return_util::validateAndCall;
WifiStaIface::WifiStaIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
: ifname_(ifname), legacy_hal_(legacy_hal), iface_util_(iface_util), is_valid_(true) {
// Turn on DFS channel usage for STA iface.
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDfsFlag(ifname_, true);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
LOG(ERROR) << "Failed to set DFS flag; DFS channels may be unavailable.";
}
}
std::shared_ptr<WifiStaIface> WifiStaIface::create(
const std::string& ifname, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util) {
std::shared_ptr<WifiStaIface> ptr =
ndk::SharedRefBase::make<WifiStaIface>(ifname, legacy_hal, iface_util);
std::weak_ptr<WifiStaIface> weak_ptr_this(ptr);
ptr->setWeakPtr(weak_ptr_this);
return ptr;
}
void WifiStaIface::invalidate() {
legacy_hal_.reset();
event_cb_handler_.invalidate();
is_valid_ = false;
}
void WifiStaIface::setWeakPtr(std::weak_ptr<WifiStaIface> ptr) {
weak_ptr_this_ = ptr;
}
bool WifiStaIface::isValid() {
return is_valid_;
}
std::string WifiStaIface::getName() {
return ifname_;
}
std::set<std::shared_ptr<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
return event_cb_handler_.getCallbacks();
}
ndk::ScopedAStatus WifiStaIface::getName(std::string* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getNameInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::registerEventCallback(
const std::shared_ptr<IWifiStaIfaceEventCallback>& in_callback) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::registerEventCallbackInternal, in_callback);
}
ndk::ScopedAStatus WifiStaIface::getCapabilities(
IWifiStaIface::StaIfaceCapabilityMask* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getCapabilitiesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::getApfPacketFilterCapabilities(
StaApfPacketFilterCapabilities* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getApfPacketFilterCapabilitiesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::installApfPacketFilter(const std::vector<uint8_t>& in_program) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::installApfPacketFilterInternal, in_program);
}
ndk::ScopedAStatus WifiStaIface::readApfPacketFilterData(std::vector<uint8_t>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::readApfPacketFilterDataInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::getBackgroundScanCapabilities(
StaBackgroundScanCapabilities* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getBackgroundScanCapabilitiesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::getValidFrequenciesForBand(WifiBand in_band,
std::vector<int32_t>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getValidFrequenciesForBandInternal, _aidl_return,
in_band);
}
ndk::ScopedAStatus WifiStaIface::startBackgroundScan(int32_t in_cmdId,
const StaBackgroundScanParameters& in_params) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::startBackgroundScanInternal, in_cmdId, in_params);
}
ndk::ScopedAStatus WifiStaIface::stopBackgroundScan(int32_t in_cmdId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::stopBackgroundScanInternal, in_cmdId);
}
ndk::ScopedAStatus WifiStaIface::enableLinkLayerStatsCollection(bool in_debug) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::enableLinkLayerStatsCollectionInternal, in_debug);
}
ndk::ScopedAStatus WifiStaIface::disableLinkLayerStatsCollection() {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::disableLinkLayerStatsCollectionInternal);
}
ndk::ScopedAStatus WifiStaIface::getLinkLayerStats(StaLinkLayerStats* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getLinkLayerStatsInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::startRssiMonitoring(int32_t in_cmdId, int32_t in_maxRssi,
int32_t in_minRssi) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::startRssiMonitoringInternal, in_cmdId, in_maxRssi,
in_minRssi);
}
ndk::ScopedAStatus WifiStaIface::stopRssiMonitoring(int32_t in_cmdId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::stopRssiMonitoringInternal, in_cmdId);
}
ndk::ScopedAStatus WifiStaIface::getRoamingCapabilities(StaRoamingCapabilities* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getRoamingCapabilitiesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::configureRoaming(const StaRoamingConfig& in_config) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::configureRoamingInternal, in_config);
}
ndk::ScopedAStatus WifiStaIface::setRoamingState(StaRoamingState in_state) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::setRoamingStateInternal, in_state);
}
ndk::ScopedAStatus WifiStaIface::enableNdOffload(bool in_enable) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::enableNdOffloadInternal, in_enable);
}
ndk::ScopedAStatus WifiStaIface::startSendingKeepAlivePackets(
int32_t in_cmdId, const std::vector<uint8_t>& in_ipPacketData, char16_t in_etherType,
const std::array<uint8_t, 6>& in_srcAddress, const std::array<uint8_t, 6>& in_dstAddress,
int32_t in_periodInMs) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::startSendingKeepAlivePacketsInternal, in_cmdId,
in_ipPacketData, in_etherType, in_srcAddress, in_dstAddress,
in_periodInMs);
}
ndk::ScopedAStatus WifiStaIface::stopSendingKeepAlivePackets(int32_t in_cmdId) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::stopSendingKeepAlivePacketsInternal, in_cmdId);
}
ndk::ScopedAStatus WifiStaIface::startDebugPacketFateMonitoring() {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::startDebugPacketFateMonitoringInternal);
}
ndk::ScopedAStatus WifiStaIface::getDebugTxPacketFates(
std::vector<WifiDebugTxPacketFateReport>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getDebugTxPacketFatesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::getDebugRxPacketFates(
std::vector<WifiDebugRxPacketFateReport>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getDebugRxPacketFatesInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::setMacAddress(const std::array<uint8_t, 6>& in_mac) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::setMacAddressInternal, in_mac);
}
ndk::ScopedAStatus WifiStaIface::getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::getFactoryMacAddressInternal, _aidl_return);
}
ndk::ScopedAStatus WifiStaIface::setScanMode(bool in_enable) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
&WifiStaIface::setScanModeInternal, in_enable);
}
std::pair<std::string, ndk::ScopedAStatus> WifiStaIface::getNameInternal() {
return {ifname_, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiStaIface::registerEventCallbackInternal(
const std::shared_ptr<IWifiStaIfaceEventCallback>& callback) {
if (!event_cb_handler_.addCallback(callback)) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
std::pair<IWifiStaIface::StaIfaceCapabilityMask, ndk::ScopedAStatus>
WifiStaIface::getCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
uint64_t legacy_feature_set;
std::tie(legacy_status, legacy_feature_set) =
legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {IWifiStaIface::StaIfaceCapabilityMask{},
createWifiStatusFromLegacyError(legacy_status)};
}
uint32_t legacy_logger_feature_set;
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_caps;
if (!aidl_struct_util::convertLegacyFeaturesToAidlStaCapabilities(
legacy_feature_set, legacy_logger_feature_set, &aidl_caps)) {
return {IWifiStaIface::StaIfaceCapabilityMask{},
createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {static_cast<IWifiStaIface::StaIfaceCapabilityMask>(aidl_caps),
ndk::ScopedAStatus::ok()};
}
std::pair<StaApfPacketFilterCapabilities, ndk::ScopedAStatus>
WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::PacketFilterCapabilities legacy_caps;
std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {StaApfPacketFilterCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
}
StaApfPacketFilterCapabilities aidl_caps;
if (!aidl_struct_util::convertLegacyApfCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
return {StaApfPacketFilterCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_caps, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiStaIface::installApfPacketFilterInternal(
const std::vector<uint8_t>& program) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setPacketFilter(ifname_, program);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus>
WifiStaIface::readApfPacketFilterDataInternal() {
const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>> legacy_status_and_data =
legacy_hal_.lock()->readApfPacketFilterData(ifname_);
return {std::move(legacy_status_and_data.second),
createWifiStatusFromLegacyError(legacy_status_and_data.first)};
}
std::pair<StaBackgroundScanCapabilities, ndk::ScopedAStatus>
WifiStaIface::getBackgroundScanCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_gscan_capabilities legacy_caps;
std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getGscanCapabilities(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {StaBackgroundScanCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
}
StaBackgroundScanCapabilities aidl_caps;
if (!aidl_struct_util::convertLegacyGscanCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
return {StaBackgroundScanCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_caps, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<int32_t>, ndk::ScopedAStatus>
WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) {
static_assert(sizeof(WifiChannelWidthInMhz) == sizeof(int32_t), "Size mismatch");
legacy_hal::wifi_error legacy_status;
std::vector<uint32_t> valid_frequencies;
std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
ifname_, aidl_struct_util::convertAidlWifiBandToLegacy(band));
return {std::vector<int32_t>(valid_frequencies.begin(), valid_frequencies.end()),
createWifiStatusFromLegacyError(legacy_status)};
}
ndk::ScopedAStatus WifiStaIface::startBackgroundScanInternal(
int32_t cmd_id, const StaBackgroundScanParameters& params) {
legacy_hal::wifi_scan_cmd_params legacy_params;
if (!aidl_struct_util::convertAidlGscanParamsToLegacy(params, &legacy_params)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
std::weak_ptr<WifiStaIface> weak_ptr_this = weak_ptr_this_;
const auto& on_failure_callback = [weak_ptr_this](legacy_hal::wifi_request_id id) {
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->onBackgroundScanFailure(id).isOk()) {
LOG(ERROR) << "Failed to invoke onBackgroundScanFailure callback";
}
}
};
const auto& on_results_callback =
[weak_ptr_this](legacy_hal::wifi_request_id id,
const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
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<StaScanData> aidl_scan_datas;
if (!aidl_struct_util::convertLegacyVectorOfCachedGscanResultsToAidl(
results, &aidl_scan_datas)) {
LOG(ERROR) << "Failed to convert scan results to AIDL structs";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->onBackgroundScanResults(id, aidl_scan_datas).isOk()) {
LOG(ERROR) << "Failed to invoke onBackgroundScanResults callback";
}
}
};
const auto& on_full_result_callback = [weak_ptr_this](
legacy_hal::wifi_request_id id,
const legacy_hal::wifi_scan_result* result,
uint32_t buckets_scanned) {
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;
}
StaScanResult aidl_scan_result;
if (!aidl_struct_util::convertLegacyGscanResultToAidl(*result, true, &aidl_scan_result)) {
LOG(ERROR) << "Failed to convert full scan results to AIDL structs";
return;
}
for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
if (!callback->onBackgroundFullScanResult(id, buckets_scanned, aidl_scan_result)
.isOk()) {
LOG(ERROR) << "Failed to invoke onBackgroundFullScanResult callback";
}
}
};
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->startGscan(ifname_, cmd_id, legacy_params, on_failure_callback,
on_results_callback, on_full_result_callback);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::stopBackgroundScanInternal(int32_t cmd_id) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableLinkLayerStats(ifname_);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<StaLinkLayerStats, ndk::ScopedAStatus> WifiStaIface::getLinkLayerStatsInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::LinkLayerStats legacy_stats;
std::tie(legacy_status, legacy_stats) = legacy_hal_.lock()->getLinkLayerStats(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {StaLinkLayerStats{}, createWifiStatusFromLegacyError(legacy_status)};
}
StaLinkLayerStats aidl_stats;
if (!aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &aidl_stats)) {
return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_stats, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiStaIface::startRssiMonitoringInternal(int32_t cmd_id, int32_t max_rssi,
int32_t min_rssi) {
std::weak_ptr<WifiStaIface> weak_ptr_this = weak_ptr_this_;
const auto& on_threshold_breached_callback =
[weak_ptr_this](legacy_hal::wifi_request_id id, std::array<uint8_t, ETH_ALEN> bssid,
int8_t rssi) {
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->onRssiThresholdBreached(id, bssid, rssi).isOk()) {
LOG(ERROR) << "Failed to invoke onRssiThresholdBreached callback";
}
}
};
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRssiMonitoring(
ifname_, cmd_id, max_rssi, min_rssi, on_threshold_breached_callback);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::stopRssiMonitoringInternal(int32_t cmd_id) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<StaRoamingCapabilities, ndk::ScopedAStatus>
WifiStaIface::getRoamingCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
legacy_hal::wifi_roaming_capabilities legacy_caps;
std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRoamingCapabilities(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {StaRoamingCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
}
StaRoamingCapabilities aidl_caps;
if (!aidl_struct_util::convertLegacyRoamingCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
return {StaRoamingCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_caps, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiStaIface::configureRoamingInternal(const StaRoamingConfig& config) {
legacy_hal::wifi_roaming_config legacy_config;
if (!aidl_struct_util::convertAidlRoamingConfigToLegacy(config, &legacy_config)) {
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
}
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableFirmwareRoaming(
ifname_, aidl_struct_util::convertAidlRoamingStateToLegacy(state));
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->configureNdOffload(ifname_, enable);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
int32_t cmd_id, const std::vector<uint8_t>& ip_packet_data, char16_t ether_type,
const std::array<uint8_t, 6>& src_address, const std::array<uint8_t, 6>& dst_address,
int32_t period_in_ms) {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startSendingOffloadedPacket(
ifname_, cmd_id, ether_type, ip_packet_data, src_address, dst_address, period_in_ms);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(int32_t cmd_id) {
legacy_hal::wifi_error legacy_status =
legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
return createWifiStatusFromLegacyError(legacy_status);
}
ndk::ScopedAStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startPktFateMonitoring(ifname_);
return createWifiStatusFromLegacyError(legacy_status);
}
std::pair<std::vector<WifiDebugTxPacketFateReport>, ndk::ScopedAStatus>
WifiStaIface::getDebugTxPacketFatesInternal() {
legacy_hal::wifi_error legacy_status;
std::vector<legacy_hal::wifi_tx_report> legacy_fates;
std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getTxPktFates(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {std::vector<WifiDebugTxPacketFateReport>(),
createWifiStatusFromLegacyError(legacy_status)};
}
std::vector<WifiDebugTxPacketFateReport> aidl_fates;
if (!aidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToAidl(legacy_fates,
&aidl_fates)) {
return {std::vector<WifiDebugTxPacketFateReport>(),
createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_fates, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<WifiDebugRxPacketFateReport>, ndk::ScopedAStatus>
WifiStaIface::getDebugRxPacketFatesInternal() {
legacy_hal::wifi_error legacy_status;
std::vector<legacy_hal::wifi_rx_report> legacy_fates;
std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getRxPktFates(ifname_);
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
return {std::vector<WifiDebugRxPacketFateReport>(),
createWifiStatusFromLegacyError(legacy_status)};
}
std::vector<WifiDebugRxPacketFateReport> aidl_fates;
if (!aidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToAidl(legacy_fates,
&aidl_fates)) {
return {std::vector<WifiDebugRxPacketFateReport>(),
createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {aidl_fates, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiStaIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
if (!status) {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> WifiStaIface::getFactoryMacAddressInternal() {
std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifname_);
if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
return {mac, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
}
return {mac, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus WifiStaIface::setScanModeInternal(bool enable) {
// OEM's need to implement this on their devices if needed.
LOG(WARNING) << "setScanModeInternal(" << enable << ") not supported";
return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,154 @@
/*
* 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.
*/
#ifndef WIFI_STA_IFACE_H_
#define WIFI_STA_IFACE_H_
#include <aidl/android/hardware/wifi/BnWifiStaIface.h>
#include <aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.h>
#include <android-base/macros.h>
#include "aidl_callback_util.h"
#include "wifi_iface_util.h"
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
/**
* AIDL interface object used to control a STA Iface instance.
*/
class WifiStaIface : public BnWifiStaIface {
public:
WifiStaIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Factory method - use instead of default constructor.
static std::shared_ptr<WifiStaIface> create(
const std::string& ifname, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
// Refer to |WifiChip::invalidate()|.
void invalidate();
bool isValid();
std::set<std::shared_ptr<IWifiStaIfaceEventCallback>> getEventCallbacks();
std::string getName();
// AIDL methods exposed.
ndk::ScopedAStatus getName(std::string* _aidl_return) override;
ndk::ScopedAStatus registerEventCallback(
const std::shared_ptr<IWifiStaIfaceEventCallback>& in_callback) override;
ndk::ScopedAStatus getCapabilities(
IWifiStaIface::StaIfaceCapabilityMask* _aidl_return) override;
ndk::ScopedAStatus getApfPacketFilterCapabilities(
StaApfPacketFilterCapabilities* _aidl_return) override;
ndk::ScopedAStatus installApfPacketFilter(const std::vector<uint8_t>& in_program) override;
ndk::ScopedAStatus readApfPacketFilterData(std::vector<uint8_t>* _aidl_return) override;
ndk::ScopedAStatus getBackgroundScanCapabilities(
StaBackgroundScanCapabilities* _aidl_return) override;
ndk::ScopedAStatus getValidFrequenciesForBand(WifiBand in_band,
std::vector<int32_t>* _aidl_return) override;
ndk::ScopedAStatus startBackgroundScan(int32_t in_cmdId,
const StaBackgroundScanParameters& in_params) override;
ndk::ScopedAStatus stopBackgroundScan(int32_t in_cmdId) override;
ndk::ScopedAStatus enableLinkLayerStatsCollection(bool in_debug) override;
ndk::ScopedAStatus disableLinkLayerStatsCollection() override;
ndk::ScopedAStatus getLinkLayerStats(StaLinkLayerStats* _aidl_return) override;
ndk::ScopedAStatus startRssiMonitoring(int32_t in_cmdId, int32_t in_maxRssi,
int32_t in_minRssi) override;
ndk::ScopedAStatus stopRssiMonitoring(int32_t in_cmdId) override;
ndk::ScopedAStatus getRoamingCapabilities(StaRoamingCapabilities* _aidl_return) override;
ndk::ScopedAStatus configureRoaming(const StaRoamingConfig& in_config) override;
ndk::ScopedAStatus setRoamingState(StaRoamingState in_state) override;
ndk::ScopedAStatus enableNdOffload(bool in_enable) override;
ndk::ScopedAStatus startSendingKeepAlivePackets(int32_t in_cmdId,
const std::vector<uint8_t>& in_ipPacketData,
char16_t in_etherType,
const std::array<uint8_t, 6>& in_srcAddress,
const std::array<uint8_t, 6>& in_dstAddress,
int32_t in_periodInMs) override;
ndk::ScopedAStatus stopSendingKeepAlivePackets(int32_t in_cmdId) override;
ndk::ScopedAStatus startDebugPacketFateMonitoring() override;
ndk::ScopedAStatus getDebugTxPacketFates(
std::vector<WifiDebugTxPacketFateReport>* _aidl_return) override;
ndk::ScopedAStatus getDebugRxPacketFates(
std::vector<WifiDebugRxPacketFateReport>* _aidl_return) override;
ndk::ScopedAStatus setMacAddress(const std::array<uint8_t, 6>& in_mac) override;
ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
ndk::ScopedAStatus setScanMode(bool in_enable) override;
private:
// Corresponding worker functions for the AIDL methods.
std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
ndk::ScopedAStatus registerEventCallbackInternal(
const std::shared_ptr<IWifiStaIfaceEventCallback>& callback);
std::pair<IWifiStaIface::StaIfaceCapabilityMask, ndk::ScopedAStatus> getCapabilitiesInternal();
std::pair<StaApfPacketFilterCapabilities, ndk::ScopedAStatus>
getApfPacketFilterCapabilitiesInternal();
ndk::ScopedAStatus installApfPacketFilterInternal(const std::vector<uint8_t>& program);
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> readApfPacketFilterDataInternal();
std::pair<StaBackgroundScanCapabilities, ndk::ScopedAStatus>
getBackgroundScanCapabilitiesInternal();
std::pair<std::vector<int32_t>, ndk::ScopedAStatus> getValidFrequenciesForBandInternal(
WifiBand band);
ndk::ScopedAStatus startBackgroundScanInternal(int32_t cmd_id,
const StaBackgroundScanParameters& params);
ndk::ScopedAStatus stopBackgroundScanInternal(int32_t cmd_id);
ndk::ScopedAStatus enableLinkLayerStatsCollectionInternal(bool debug);
ndk::ScopedAStatus disableLinkLayerStatsCollectionInternal();
std::pair<StaLinkLayerStats, ndk::ScopedAStatus> getLinkLayerStatsInternal();
ndk::ScopedAStatus startRssiMonitoringInternal(int32_t cmd_id, int32_t max_rssi,
int32_t min_rssi);
ndk::ScopedAStatus stopRssiMonitoringInternal(int32_t cmd_id);
std::pair<StaRoamingCapabilities, ndk::ScopedAStatus> getRoamingCapabilitiesInternal();
ndk::ScopedAStatus configureRoamingInternal(const StaRoamingConfig& config);
ndk::ScopedAStatus setRoamingStateInternal(StaRoamingState state);
ndk::ScopedAStatus enableNdOffloadInternal(bool enable);
ndk::ScopedAStatus startSendingKeepAlivePacketsInternal(
int32_t cmd_id, const std::vector<uint8_t>& ip_packet_data, char16_t ether_type,
const std::array<uint8_t, 6>& src_address, const std::array<uint8_t, 6>& dst_address,
int32_t period_in_ms);
ndk::ScopedAStatus stopSendingKeepAlivePacketsInternal(int32_t cmd_id);
ndk::ScopedAStatus startDebugPacketFateMonitoringInternal();
std::pair<std::vector<WifiDebugTxPacketFateReport>, ndk::ScopedAStatus>
getDebugTxPacketFatesInternal();
std::pair<std::vector<WifiDebugRxPacketFateReport>, ndk::ScopedAStatus>
getDebugRxPacketFatesInternal();
ndk::ScopedAStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getFactoryMacAddressInternal();
ndk::ScopedAStatus setScanModeInternal(bool enable);
void setWeakPtr(std::weak_ptr<WifiStaIface> ptr);
std::string ifname_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
std::weak_ptr<WifiStaIface> weak_ptr_this_;
bool is_valid_;
aidl_callback_util::AidlCallbackHandler<IWifiStaIfaceEventCallback> event_cb_handler_;
DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
};
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_STA_IFACE_H_

View File

@@ -0,0 +1,106 @@
/*
* 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_status_util.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
std::string legacyErrorToString(legacy_hal::wifi_error error) {
switch (error) {
case legacy_hal::WIFI_SUCCESS:
return "SUCCESS";
case legacy_hal::WIFI_ERROR_UNINITIALIZED:
return "UNINITIALIZED";
case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
return "NOT_AVAILABLE";
case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
return "NOT_SUPPORTED";
case legacy_hal::WIFI_ERROR_INVALID_ARGS:
return "INVALID_ARGS";
case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
return "INVALID_REQUEST_ID";
case legacy_hal::WIFI_ERROR_TIMED_OUT:
return "TIMED_OUT";
case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
return "TOO_MANY_REQUESTS";
case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
return "OUT_OF_MEMORY";
case legacy_hal::WIFI_ERROR_BUSY:
return "BUSY";
case legacy_hal::WIFI_ERROR_UNKNOWN:
return "UNKNOWN";
default:
return "UNKNOWN ERROR";
}
}
ndk::ScopedAStatus createWifiStatus(WifiStatusCode code, const std::string& description) {
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(static_cast<int32_t>(code),
description.c_str());
}
ndk::ScopedAStatus createWifiStatus(WifiStatusCode code) {
return ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(code));
}
ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
const std::string& desc) {
switch (error) {
case legacy_hal::WIFI_ERROR_NONE:
return ndk::ScopedAStatus::ok();
case legacy_hal::WIFI_ERROR_UNINITIALIZED:
case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
case legacy_hal::WIFI_ERROR_INVALID_ARGS:
case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
case legacy_hal::WIFI_ERROR_TIMED_OUT:
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", timed out");
case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", too many requests");
case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", out of memory");
case legacy_hal::WIFI_ERROR_BUSY:
return createWifiStatus(WifiStatusCode::ERROR_BUSY);
case legacy_hal::WIFI_ERROR_UNKNOWN:
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
default:
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown error");
}
}
ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
return createWifiStatusFromLegacyError(error, "");
}
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef WIFI_STATUS_UTIL_H_
#define WIFI_STATUS_UTIL_H_
#include <aidl/android/hardware/wifi/IWifi.h>
#include "wifi_legacy_hal.h"
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
using ::aidl::android::hardware::wifi::WifiStatusCode;
std::string legacyErrorToString(legacy_hal::wifi_error error);
ndk::ScopedAStatus createWifiStatus(WifiStatusCode code, const std::string& description);
ndk::ScopedAStatus createWifiStatus(WifiStatusCode code);
ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
const std::string& description);
ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // WIFI_STATUS_UTIL_H_

View File

@@ -0,0 +1,169 @@
//
// 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.
//
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_test {
name: "VtsHalWifiChipTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"wifi_chip_aidl_test.cpp",
],
shared_libs: [
"libbinder",
"libbinder_ndk",
"libvndksupport",
],
static_libs: [
"VtsHalWifiTargetTestUtil",
"android.hardware.wifi-V1-ndk",
"libwifi-system-iface",
],
test_suites: [
"general-tests",
"vts",
],
}
cc_test {
name: "VtsHalWifiStaIfaceTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"wifi_sta_iface_aidl_test.cpp",
],
shared_libs: [
"libbinder",
"libbinder_ndk",
"libvndksupport",
],
static_libs: [
"VtsHalWifiTargetTestUtil",
"android.hardware.wifi-V1-ndk",
"libwifi-system-iface",
],
test_suites: [
"general-tests",
"vts",
],
}
cc_test {
name: "VtsHalWifiApIfaceTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"wifi_ap_iface_aidl_test.cpp",
],
shared_libs: [
"libbinder",
"libbinder_ndk",
"libvndksupport",
],
static_libs: [
"VtsHalWifiTargetTestUtil",
"android.hardware.wifi-V1-ndk",
"libwifi-system-iface",
],
test_suites: [
"general-tests",
"vts",
],
}
cc_test {
name: "VtsHalWifiNanIfaceTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"wifi_nan_iface_aidl_test.cpp",
],
shared_libs: [
"libbinder",
"libbinder_ndk",
"libvndksupport",
],
static_libs: [
"VtsHalWifiTargetTestUtil",
"android.hardware.wifi-V1-ndk",
"libwifi-system-iface",
],
test_suites: [
"general-tests",
"vts",
],
}
cc_test {
name: "VtsHalWifiRttControllerTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"wifi_rtt_controller_aidl_test.cpp",
],
shared_libs: [
"libbinder",
"libbinder_ndk",
"libvndksupport",
],
static_libs: [
"VtsHalWifiTargetTestUtil",
"android.hardware.wifi-V1-ndk",
"libwifi-system-iface",
],
test_suites: [
"general-tests",
"vts",
],
}
cc_library_static {
name: "VtsHalWifiTargetTestUtil",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"wifi_aidl_test_utils.cpp",
],
export_include_dirs: [
".",
],
shared_libs: [
"libbinder",
"libbinder_ndk",
"libnativehelper",
],
static_libs: [
"android.hardware.wifi-V1-ndk",
"libwifi-system-iface",
],
}

View File

@@ -0,0 +1,216 @@
/*
* 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_aidl_test_utils.h"
using ::android::wifi_system::InterfaceTool;
namespace {
bool findAnyModeSupportingConcurrencyType(IfaceConcurrencyType desired_type,
const std::vector<IWifiChip::ChipMode>& modes,
int* mode_id) {
for (const auto& mode : modes) {
for (const auto& combination : mode.availableCombinations) {
for (const auto& iface_limit : combination.limits) {
const auto& iface_types = iface_limit.types;
if (std::find(iface_types.begin(), iface_types.end(), desired_type) !=
iface_types.end()) {
*mode_id = mode.id;
return true;
}
}
}
}
return false;
}
bool configureChipToSupportConcurrencyTypeInternal(const std::shared_ptr<IWifiChip>& wifi_chip,
IfaceConcurrencyType type,
int* configured_mode_id) {
if (!configured_mode_id) {
return false;
}
std::vector<IWifiChip::ChipMode> chip_modes;
auto status = wifi_chip->getAvailableModes(&chip_modes);
if (!status.isOk()) {
return false;
}
if (!findAnyModeSupportingConcurrencyType(type, chip_modes, configured_mode_id)) {
return false;
}
if (!wifi_chip->configureChip(*configured_mode_id).isOk()) {
return false;
}
return true;
}
bool configureChipToSupportConcurrencyTypeInternal(const std::shared_ptr<IWifiChip>& wifi_chip,
IfaceConcurrencyType type) {
int mode_id;
return configureChipToSupportConcurrencyTypeInternal(wifi_chip, type, &mode_id);
}
} // namespace
bool checkStatusCode(ndk::ScopedAStatus* status, WifiStatusCode expected_code) {
if (status == nullptr) {
return false;
}
return status->getServiceSpecificError() == static_cast<int32_t>(expected_code);
}
std::shared_ptr<IWifi> getWifi(const char* instance_name) {
return IWifi::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(instance_name)));
}
std::shared_ptr<IWifiChip> getWifiChip(const char* instance_name) {
std::shared_ptr<IWifi> wifi = getWifi(instance_name);
if (!wifi.get()) {
return nullptr;
}
const int retry_interval_ms = 2;
const int max_retries = 5;
int retry_count = 0;
auto status = wifi->start();
while (retry_count < max_retries && !status.isOk()) {
retry_count++;
usleep(retry_interval_ms * 1000);
status = wifi->start();
}
if (!status.isOk()) {
return nullptr;
}
std::vector<int> chip_ids = {};
status = wifi->getChipIds(&chip_ids);
if (!status.isOk() || chip_ids.size() == 0) {
return nullptr;
}
std::shared_ptr<IWifiChip> chip;
status = wifi->getChip(chip_ids[0], &chip);
if (!status.isOk()) {
return nullptr;
}
return chip;
}
void setupStaIface(const std::shared_ptr<IWifiStaIface>& iface) {
std::string iface_name;
auto status = iface->getName(&iface_name);
if (status.isOk()) {
InterfaceTool iface_tool;
iface_tool.SetUpState(iface_name.c_str(), true);
}
}
void setupNanIface(const std::shared_ptr<IWifiNanIface>& iface) {
std::string iface_name;
auto status = iface->getName(&iface_name);
if (status.isOk()) {
InterfaceTool iface_tool;
iface_tool.SetUpState(iface_name.c_str(), true);
}
}
std::shared_ptr<IWifiStaIface> getWifiStaIface(const char* instance_name) {
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
if (!wifi_chip.get()) {
return nullptr;
}
if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::STA)) {
return nullptr;
}
std::shared_ptr<IWifiStaIface> iface;
auto status = wifi_chip->createStaIface(&iface);
if (!status.isOk()) {
return nullptr;
}
setupStaIface(iface);
return iface;
}
std::shared_ptr<IWifiNanIface> getWifiNanIface(const char* instance_name) {
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
if (!wifi_chip.get()) {
return nullptr;
}
if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip,
IfaceConcurrencyType::NAN_IFACE)) {
return nullptr;
}
std::shared_ptr<IWifiNanIface> iface;
auto status = wifi_chip->createNanIface(&iface);
if (!status.isOk()) {
return nullptr;
}
setupNanIface(iface);
return iface;
}
std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name) {
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
if (!wifi_chip.get()) {
return nullptr;
}
if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::AP)) {
return nullptr;
}
std::shared_ptr<IWifiApIface> iface;
auto status = wifi_chip->createApIface(&iface);
if (!status.isOk()) {
return nullptr;
}
return iface;
}
std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip) {
if (!wifi_chip.get()) {
return nullptr;
}
int mode_id;
std::shared_ptr<IWifiApIface> iface;
configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::AP, &mode_id);
auto status = wifi_chip->createBridgedApIface(&iface);
if (!status.isOk()) {
return nullptr;
}
return iface;
}
std::shared_ptr<IWifiApIface> getBridgedWifiApIface(const char* instance_name) {
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
return getBridgedWifiApIface(wifi_chip);
}
bool configureChipToSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
IfaceConcurrencyType type, int* configured_mode_id) {
return configureChipToSupportConcurrencyTypeInternal(wifi_chip, type, configured_mode_id);
}
void stopWifiService(const char* instance_name) {
std::shared_ptr<IWifi> wifi = getWifi(instance_name);
if (wifi != nullptr) {
wifi->stop();
}
}
int32_t getChipCapabilities(const std::shared_ptr<IWifiChip>& wifi_chip) {
IWifiChip::ChipCapabilityMask caps = {};
if (wifi_chip->getCapabilities(&caps).isOk()) {
return static_cast<int32_t>(caps);
}
return 0;
}

View File

@@ -0,0 +1,48 @@
/*
* 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.
*/
#pragma once
#include <VtsCoreUtil.h>
#include <aidl/android/hardware/wifi/IWifi.h>
#include <aidl/android/hardware/wifi/IWifiChip.h>
#include <android/binder_manager.h>
#include <wifi_system/interface_tool.h>
using aidl::android::hardware::wifi::IfaceConcurrencyType;
using aidl::android::hardware::wifi::IWifi;
using aidl::android::hardware::wifi::IWifiApIface;
using aidl::android::hardware::wifi::IWifiChip;
using aidl::android::hardware::wifi::IWifiNanIface;
using aidl::android::hardware::wifi::IWifiStaIface;
using aidl::android::hardware::wifi::WifiStatusCode;
// Helper functions to obtain references to the various AIDL interface objects.
std::shared_ptr<IWifi> getWifi(const char* instance_name);
std::shared_ptr<IWifiChip> getWifiChip(const char* instance_name);
std::shared_ptr<IWifiStaIface> getWifiStaIface(const char* instance_name);
std::shared_ptr<IWifiNanIface> getWifiNanIface(const char* instance_name);
std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name);
std::shared_ptr<IWifiApIface> getBridgedWifiApIface(const char* instance_name);
std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
// Configure the chip in a mode to support the creation of the provided iface type.
bool configureChipToSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
IfaceConcurrencyType type, int* configured_mode_id);
// Used to trigger IWifi.stop() at the end of every test.
void stopWifiService(const char* instance_name);
int32_t getChipCapabilities(const std::shared_ptr<IWifiChip>& wifi_chip);
bool checkStatusCode(ndk::ScopedAStatus* status, WifiStatusCode expected_code);

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Staache 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 <vector>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/wifi/BnWifi.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "wifi_aidl_test_utils.h"
using aidl::android::hardware::wifi::IWifiApIface;
using aidl::android::hardware::wifi::WifiBand;
class WifiApIfaceAidlTest : public testing::TestWithParam<std::string> {
public:
void SetUp() override {
isBridgedSupport_ = testing::checkSubstringInCommandOutput(
"/system/bin/cmd wifi get-softap-supported-features",
"wifi_softap_bridged_ap_supported");
stopWifiService(getInstanceName());
}
void TearDown() override { stopWifiService(getInstanceName()); }
protected:
bool isBridgedSupport_ = false;
const char* getInstanceName() { return GetParam().c_str(); }
};
/*
* SetMacAddress
*/
TEST_P(WifiApIfaceAidlTest, SetMacAddress) {
std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
std::array<uint8_t, 6> mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x44};
EXPECT_TRUE(wifi_ap_iface->setMacAddress(mac).isOk());
}
/*
* SetCountryCode
*/
TEST_P(WifiApIfaceAidlTest, SetCountryCode) {
std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
const std::array<uint8_t, 2> country_code = {0x55, 0x53};
EXPECT_TRUE(wifi_ap_iface->setCountryCode(country_code).isOk());
}
/*
* GetValidFrequenciesForBand
* Ensures that we can retrieve valid frequencies for the 2.4 GHz band.
*/
TEST_P(WifiApIfaceAidlTest, GetValidFrequenciesForBand) {
std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
std::vector<int32_t> freqs;
EXPECT_TRUE(wifi_ap_iface->getValidFrequenciesForBand(WifiBand::BAND_24GHZ, &freqs).isOk());
EXPECT_NE(freqs.size(), 0);
}
/*
* GetFactoryMacAddress
*/
TEST_P(WifiApIfaceAidlTest, GetFactoryMacAddress) {
std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
std::array<uint8_t, 6> mac;
EXPECT_TRUE(wifi_ap_iface->getFactoryMacAddress(&mac).isOk());
std::array<uint8_t, 6> all_zero_mac = {0, 0, 0, 0, 0, 0};
EXPECT_NE(mac, all_zero_mac);
}
/**
* GetBridgedInstances - non-bridged mode
*/
TEST_P(WifiApIfaceAidlTest, GetBridgedInstances) {
std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
std::vector<std::string> instances;
EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
EXPECT_EQ(instances.size(), 0);
}
/**
* GetBridgedInstances - bridged AP mode.
*/
TEST_P(WifiApIfaceAidlTest, GetBridgedInstances_Bridged) {
if (!isBridgedSupport_) {
GTEST_SKIP() << "Missing Bridged AP support";
}
std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
std::vector<std::string> instances;
EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
EXPECT_EQ(instances.size(), 2);
}
/**
* ResetToFactoryMacAddress - non-bridged mode
*/
TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress) {
std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
}
/**
* ResetToFactoryMacAddress - bridged AP mode
*/
TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress_Bridged) {
if (!isBridgedSupport_) {
GTEST_SKIP() << "Missing Bridged AP support";
}
std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
ASSERT_NE(nullptr, wifi_ap_iface.get());
EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiApIfaceAidlTest);
INSTANTIATE_TEST_SUITE_P(WifiTest, WifiApIfaceAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
android::ProcessState::self()->startThreadPool();
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,889 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Staache 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 <numeric>
#include <vector>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/wifi/BnWifi.h>
#include <aidl/android/hardware/wifi/BnWifiChipEventCallback.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "wifi_aidl_test_utils.h"
using aidl::android::hardware::wifi::BnWifiChipEventCallback;
using aidl::android::hardware::wifi::IfaceType;
using aidl::android::hardware::wifi::IWifiApIface;
using aidl::android::hardware::wifi::IWifiChip;
using aidl::android::hardware::wifi::IWifiNanIface;
using aidl::android::hardware::wifi::IWifiP2pIface;
using aidl::android::hardware::wifi::IWifiRttController;
using aidl::android::hardware::wifi::WifiBand;
using aidl::android::hardware::wifi::WifiDebugHostWakeReasonStats;
using aidl::android::hardware::wifi::WifiDebugRingBufferStatus;
using aidl::android::hardware::wifi::WifiDebugRingBufferVerboseLevel;
using aidl::android::hardware::wifi::WifiIfaceMode;
using aidl::android::hardware::wifi::WifiRadioCombinationMatrix;
using aidl::android::hardware::wifi::WifiStatusCode;
using aidl::android::hardware::wifi::WifiUsableChannel;
class WifiChipAidlTest : public testing::TestWithParam<std::string> {
public:
void SetUp() override {
stopWifiService(getInstanceName());
wifi_chip_ = getWifiChip(getInstanceName());
ASSERT_NE(nullptr, wifi_chip_.get());
}
void TearDown() override { stopWifiService(getInstanceName()); }
protected:
int configureChipForConcurrencyType(IfaceConcurrencyType type) {
int mode_id;
EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip_, type, &mode_id));
return mode_id;
}
std::shared_ptr<IWifiStaIface> configureChipForStaAndGetIface() {
std::shared_ptr<IWifiStaIface> iface;
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
EXPECT_TRUE(wifi_chip_->createStaIface(&iface).isOk());
EXPECT_NE(nullptr, iface.get());
return iface;
}
std::shared_ptr<IWifiP2pIface> configureChipForP2pAndGetIface() {
std::shared_ptr<IWifiP2pIface> iface;
configureChipForConcurrencyType(IfaceConcurrencyType::P2P);
EXPECT_TRUE(wifi_chip_->createP2pIface(&iface).isOk());
EXPECT_NE(nullptr, iface.get());
return iface;
}
std::shared_ptr<IWifiApIface> configureChipForApAndGetIface() {
std::shared_ptr<IWifiApIface> iface;
configureChipForConcurrencyType(IfaceConcurrencyType::AP);
EXPECT_TRUE(wifi_chip_->createApIface(&iface).isOk());
EXPECT_NE(nullptr, iface.get());
return iface;
}
std::shared_ptr<IWifiNanIface> configureChipForNanAndGetIface() {
std::shared_ptr<IWifiNanIface> iface;
configureChipForConcurrencyType(IfaceConcurrencyType::NAN_IFACE);
EXPECT_TRUE(wifi_chip_->createNanIface(&iface).isOk());
EXPECT_NE(nullptr, iface.get());
return iface;
}
std::string getStaIfaceName(const std::shared_ptr<IWifiStaIface>& iface) {
std::string iface_name;
EXPECT_TRUE(iface->getName(&iface_name).isOk());
return iface_name;
}
std::string getP2pIfaceName(const std::shared_ptr<IWifiP2pIface>& iface) {
std::string iface_name;
EXPECT_TRUE(iface->getName(&iface_name).isOk());
return iface_name;
}
std::string getApIfaceName(const std::shared_ptr<IWifiApIface>& iface) {
std::string iface_name;
EXPECT_TRUE(iface->getName(&iface_name).isOk());
return iface_name;
}
std::string getNanIfaceName(const std::shared_ptr<IWifiNanIface>& iface) {
std::string iface_name;
EXPECT_TRUE(iface->getName(&iface_name).isOk());
return iface_name;
}
std::vector<std::shared_ptr<IWifiStaIface>> create2StaIfacesIfPossible() {
std::shared_ptr<IWifiStaIface> iface1 = configureChipForStaAndGetIface();
// Try create a create second iface.
std::shared_ptr<IWifiStaIface> iface2;
bool add_second_success = wifi_chip_->createStaIface(&iface2).isOk();
if (!add_second_success) {
return {iface1};
}
EXPECT_NE(nullptr, iface2.get());
return {iface1, iface2};
}
bool hasAnyRingBufferCapabilities(int32_t caps) {
return caps &
(static_cast<int32_t>(
IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_CONNECT_EVENT) |
static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_POWER_EVENT) |
static_cast<int32_t>(
IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_WAKELOCK_EVENT) |
static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_VENDOR_DATA));
}
const char* getInstanceName() { return GetParam().c_str(); }
std::shared_ptr<IWifiChip> wifi_chip_;
};
class WifiChipEventCallback : public BnWifiChipEventCallback {
public:
WifiChipEventCallback() = default;
::ndk::ScopedAStatus onChipReconfigureFailure(WifiStatusCode /* status */) override {
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus onChipReconfigured(int /* modeId */) override {
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus onDebugErrorAlert(int /* errorCode */,
const std::vector<uint8_t>& /* debugData */) override {
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus onDebugRingBufferDataAvailable(
const WifiDebugRingBufferStatus& /* status */,
const std::vector<uint8_t>& /* data */) override {
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus onIfaceAdded(IfaceType /* type */,
const std::string& /* name */) override {
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus onIfaceRemoved(IfaceType /* type */,
const std::string& /* name */) override {
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus onRadioModeChange(
const std::vector<RadioModeInfo>& /* radioModeInfos */) override {
return ndk::ScopedAStatus::ok();
}
};
/*
* RegisterEventCallback
*
* Note: it is not feasible to test the invocation of the callback function,
* since events are triggered internally in the HAL implementation and cannot be
* triggered from the test case.
*/
TEST_P(WifiChipAidlTest, RegisterEventCallback) {
std::shared_ptr<WifiChipEventCallback> callback =
ndk::SharedRefBase::make<WifiChipEventCallback>();
ASSERT_NE(nullptr, callback.get());
EXPECT_TRUE(wifi_chip_->registerEventCallback(callback).isOk());
}
/*
* GetCapabilities
*/
TEST_P(WifiChipAidlTest, GetCapabilities) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
EXPECT_NE(static_cast<int32_t>(caps), 0);
}
/*
* GetId
*/
TEST_P(WifiChipAidlTest, GetId) {
int id;
EXPECT_TRUE(wifi_chip_->getId(&id).isOk());
}
/*
* GetAvailableModes
*/
TEST_P(WifiChipAidlTest, GetAvailableModes) {
std::vector<IWifiChip::ChipMode> modes;
EXPECT_TRUE(wifi_chip_->getAvailableModes(&modes).isOk());
EXPECT_NE(modes.size(), 0);
}
/*
* GetMode
*/
TEST_P(WifiChipAidlTest, GetMode) {
int expected_mode = configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int retrieved_mode;
EXPECT_TRUE(wifi_chip_->getMode(&retrieved_mode).isOk());
EXPECT_EQ(retrieved_mode, expected_mode);
}
/*
* GetUsableChannels
*/
TEST_P(WifiChipAidlTest, GetUsableChannels) {
WifiBand band = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
uint32_t ifaceModeMask = static_cast<uint32_t>(WifiIfaceMode::IFACE_MODE_P2P_CLIENT) |
static_cast<uint32_t>(WifiIfaceMode::IFACE_MODE_P2P_GO);
uint32_t filterMask =
static_cast<uint32_t>(IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) |
static_cast<uint32_t>(IWifiChip::UsableChannelFilter::CONCURRENCY);
std::vector<WifiUsableChannel> channels;
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
auto status = wifi_chip_->getUsableChannels(
band, static_cast<WifiIfaceMode>(ifaceModeMask),
static_cast<IWifiChip::UsableChannelFilter>(filterMask), &channels);
if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
GTEST_SKIP() << "getUsableChannels() is not supported by vendor.";
}
EXPECT_TRUE(status.isOk());
}
/*
* GetSupportedRadioCombinationsMatrix
*/
TEST_P(WifiChipAidlTest, GetSupportedRadioCombinationsMatrix) {
WifiRadioCombinationMatrix combination_matrix = {};
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
auto status = wifi_chip_->getSupportedRadioCombinationsMatrix(&combination_matrix);
if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
GTEST_SKIP() << "Skipping this test since getSupportedRadioCombinationsMatrix() "
"is not supported by vendor.";
}
EXPECT_TRUE(status.isOk());
}
/*
* SetCountryCode
*/
TEST_P(WifiChipAidlTest, SetCountryCode) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
std::array<uint8_t, 2> country_code = {0x55, 0x53};
EXPECT_TRUE(wifi_chip_->setCountryCode(country_code).isOk());
}
/*
* SetLatencyMode_normal
* Tests the setLatencyMode() API with Latency mode NORMAL.
*/
TEST_P(WifiChipAidlTest, SetLatencyMode_normal) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
auto status = wifi_chip_->setLatencyMode(IWifiChip::LatencyMode::NORMAL);
if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* SetLatencyMode_low
* Tests the setLatencyMode() API with Latency mode LOW.
*/
TEST_P(WifiChipAidlTest, SetLatencyMode_low) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
auto status = wifi_chip_->setLatencyMode(IWifiChip::LatencyMode::LOW);
if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* SetMultiStaPrimaryConnection
*
* Only runs if the device supports 2 STA ifaces.
*/
TEST_P(WifiChipAidlTest, SetMultiStaPrimaryConnection) {
auto ifaces = create2StaIfacesIfPossible();
if (ifaces.size() < 2) {
GTEST_SKIP() << "Device does not support more than 1 STA concurrently";
}
auto status = wifi_chip_->setMultiStaPrimaryConnection(getStaIfaceName(ifaces[0]));
if (!status.isOk()) {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* SetMultiStaUseCase
*
* Only runs if the device supports 2 STA ifaces.
*/
TEST_P(WifiChipAidlTest, setMultiStaUseCase) {
auto ifaces = create2StaIfacesIfPossible();
if (ifaces.size() < 2) {
GTEST_SKIP() << "Device does not support more than 1 STA concurrently";
}
auto status = wifi_chip_->setMultiStaUseCase(
IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY);
if (!status.isOk()) {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* SetCoexUnsafeChannels
*/
TEST_P(WifiChipAidlTest, SetCoexUnsafeChannels) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
// Test with an empty vector of CoexUnsafeChannels.
std::vector<IWifiChip::CoexUnsafeChannel> vec;
IWifiChip::CoexRestriction restrictions = static_cast<IWifiChip::CoexRestriction>(0);
auto status = wifi_chip_->setCoexUnsafeChannels(vec, restrictions);
if (!status.isOk()) {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
// Test with a non-empty vector of CoexUnsafeChannels.
IWifiChip::CoexUnsafeChannel unsafeChannel24Ghz;
unsafeChannel24Ghz.band = WifiBand::BAND_24GHZ;
unsafeChannel24Ghz.channel = 6;
vec.push_back(unsafeChannel24Ghz);
IWifiChip::CoexUnsafeChannel unsafeChannel5Ghz;
unsafeChannel5Ghz.band = WifiBand::BAND_5GHZ;
unsafeChannel5Ghz.channel = 36;
vec.push_back(unsafeChannel5Ghz);
restrictions = static_cast<IWifiChip::CoexRestriction>(
static_cast<int32_t>(IWifiChip::CoexRestriction::WIFI_AWARE) |
static_cast<int32_t>(IWifiChip::CoexRestriction::SOFTAP) |
static_cast<int32_t>(IWifiChip::CoexRestriction::WIFI_DIRECT));
status = wifi_chip_->setCoexUnsafeChannels(vec, restrictions);
if (!status.isOk()) {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* SelectTxPowerScenario - Body
*/
TEST_P(WifiChipAidlTest, SelectTxPowerScenario_body) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
int32_t expected_caps =
static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT) |
static_cast<int32_t>(IWifiChip::ChipCapabilityMask::USE_BODY_HEAD_SAR);
auto status = wifi_chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF);
if (caps & expected_caps) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* SelectTxPowerScenario - Voice Call
*/
TEST_P(WifiChipAidlTest, SelectTxPowerScenario_voiceCall) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
auto status = wifi_chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::VOICE_CALL);
if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* ResetTxPowerScenario
*/
TEST_P(WifiChipAidlTest, ResetTxPowerScenario) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
auto status = wifi_chip_->resetTxPowerScenario();
if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* ConfigureChip
*/
TEST_P(WifiChipAidlTest, ConfigureChip) {
std::vector<IWifiChip::ChipMode> modes;
EXPECT_TRUE(wifi_chip_->getAvailableModes(&modes).isOk());
EXPECT_NE(modes.size(), 0);
for (const auto& mode : modes) {
// configureChip() requires a fresh IWifiChip object.
wifi_chip_ = getWifiChip(getInstanceName());
ASSERT_NE(nullptr, wifi_chip_.get());
EXPECT_TRUE(wifi_chip_->configureChip(mode.id).isOk());
stopWifiService(getInstanceName());
// Sleep for 5 milliseconds between each wifi state toggle.
usleep(5000);
}
}
/*
* RequestChipDebugInfo
*/
TEST_P(WifiChipAidlTest, RequestChipDebugInfo) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
IWifiChip::ChipDebugInfo debug_info = {};
EXPECT_TRUE(wifi_chip_->requestChipDebugInfo(&debug_info).isOk());
EXPECT_NE(debug_info.driverDescription.size(), 0);
EXPECT_NE(debug_info.firmwareDescription.size(), 0);
}
/*
* RequestFirmwareDebugDump
*/
TEST_P(WifiChipAidlTest, RequestFirmwareDebugDump) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
std::vector<uint8_t> debug_dump;
auto status = wifi_chip_->requestFirmwareDebugDump(&debug_dump);
if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_FIRMWARE_DUMP)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* RequestDriverDebugDump
*/
TEST_P(WifiChipAidlTest, RequestDriverDebugDump) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
std::vector<uint8_t> debug_dump;
auto status = wifi_chip_->requestDriverDebugDump(&debug_dump);
if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_DRIVER_DUMP)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* GetDebugRingBuffersStatus
*/
TEST_P(WifiChipAidlTest, GetDebugRingBuffersStatus) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
std::vector<WifiDebugRingBufferStatus> ring_buffer_status;
auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status);
if (hasAnyRingBufferCapabilities(caps)) {
EXPECT_TRUE(status.isOk());
ASSERT_NE(ring_buffer_status.size(), 0);
for (const auto& ring_buffer : ring_buffer_status) {
EXPECT_NE(ring_buffer.ringName.size(), 0);
}
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* GetDebugHostWakeReasonStats
*/
TEST_P(WifiChipAidlTest, GetDebugHostWakeReasonStats) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
WifiDebugHostWakeReasonStats wake_reason_stats = {};
auto status = wifi_chip_->getDebugHostWakeReasonStats(&wake_reason_stats);
if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_HOST_WAKE_REASON_STATS)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* StartLoggingToDebugRingBuffer
*/
TEST_P(WifiChipAidlTest, StartLoggingToDebugRingBuffer) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
std::string ring_name;
std::vector<WifiDebugRingBufferStatus> ring_buffer_status;
auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status);
if (hasAnyRingBufferCapabilities(caps)) {
EXPECT_TRUE(status.isOk());
ASSERT_NE(ring_buffer_status.size(), 0);
ring_name = ring_buffer_status[0].ringName;
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
status = wifi_chip_->startLoggingToDebugRingBuffer(
ring_name, WifiDebugRingBufferVerboseLevel::VERBOSE, 5, 1024);
if (hasAnyRingBufferCapabilities(caps)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* ForceDumpToDebugRingBuffer
*/
TEST_P(WifiChipAidlTest, ForceDumpToDebugRingBuffer) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
int32_t caps = getChipCapabilities(wifi_chip_);
std::string ring_name;
std::vector<WifiDebugRingBufferStatus> ring_buffer_status;
auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status);
if (hasAnyRingBufferCapabilities(caps)) {
EXPECT_TRUE(status.isOk());
ASSERT_NE(ring_buffer_status.size(), 0);
ring_name = ring_buffer_status[0].ringName;
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
status = wifi_chip_->forceDumpToDebugRingBuffer(ring_name);
if (hasAnyRingBufferCapabilities(caps)) {
EXPECT_TRUE(status.isOk());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/*
* CreateStaIface
* Configures the chip in STA mode and creates an iface.
*/
TEST_P(WifiChipAidlTest, CreateStaIface) {
configureChipForStaAndGetIface();
}
/*
* CreateApIface
*/
TEST_P(WifiChipAidlTest, CreateApIface) {
configureChipForApAndGetIface();
}
/*
* CreateNanIface
*/
TEST_P(WifiChipAidlTest, CreateNanIface) {
configureChipForNanAndGetIface();
}
/*
* CreateP2pIface
*/
TEST_P(WifiChipAidlTest, CreateP2pIface) {
configureChipForNanAndGetIface();
}
/*
* GetStaIfaceNames
* Configures the chip in STA mode and ensures that the iface name list is
* empty before creating the iface. Then create the iface and ensure that
* iface name is returned in the iface name list.
*/
TEST_P(WifiChipAidlTest, GetStaIfaceNames) {
configureChipForConcurrencyType(IfaceConcurrencyType::STA);
std::vector<std::string> iface_names;
EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
std::shared_ptr<IWifiStaIface> iface;
EXPECT_TRUE(wifi_chip_->createStaIface(&iface).isOk());
ASSERT_NE(nullptr, iface.get());
std::string iface_name = getStaIfaceName(iface);
EXPECT_TRUE(wifi_chip_->getStaIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 1);
EXPECT_EQ(iface_name, iface_names[0]);
EXPECT_TRUE(wifi_chip_->removeStaIface(iface_name).isOk());
EXPECT_TRUE(wifi_chip_->getStaIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
}
/*
* GetP2pIfaceNames
*/
TEST_P(WifiChipAidlTest, GetP2pIfaceNames) {
configureChipForConcurrencyType(IfaceConcurrencyType::P2P);
std::vector<std::string> iface_names;
EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
std::shared_ptr<IWifiP2pIface> iface;
EXPECT_TRUE(wifi_chip_->createP2pIface(&iface).isOk());
ASSERT_NE(nullptr, iface.get());
std::string iface_name = getP2pIfaceName(iface);
EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 1);
EXPECT_EQ(iface_name, iface_names[0]);
EXPECT_TRUE(wifi_chip_->removeP2pIface(iface_name).isOk());
EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
}
/*
* GetApIfaceNames
*/
TEST_P(WifiChipAidlTest, GetApIfaceNames) {
configureChipForConcurrencyType(IfaceConcurrencyType::AP);
std::vector<std::string> iface_names;
EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
std::shared_ptr<IWifiApIface> iface;
EXPECT_TRUE(wifi_chip_->createApIface(&iface).isOk());
ASSERT_NE(nullptr, iface.get());
std::string iface_name = getApIfaceName(iface);
EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 1);
EXPECT_EQ(iface_name, iface_names[0]);
EXPECT_TRUE(wifi_chip_->removeApIface(iface_name).isOk());
EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
}
/*
* GetNanIfaceNames
*/
TEST_P(WifiChipAidlTest, GetNanIfaceNames) {
configureChipForConcurrencyType(IfaceConcurrencyType::NAN_IFACE);
std::vector<std::string> iface_names;
EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
std::shared_ptr<IWifiNanIface> iface;
EXPECT_TRUE(wifi_chip_->createNanIface(&iface).isOk());
ASSERT_NE(nullptr, iface.get());
std::string iface_name = getNanIfaceName(iface);
EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 1);
EXPECT_EQ(iface_name, iface_names[0]);
EXPECT_TRUE(wifi_chip_->removeNanIface(iface_name).isOk());
EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk());
EXPECT_EQ(iface_names.size(), 0);
}
/*
* GetStaIface
* Configures the chip in STA mode and creates an iface. Then retrieves
* the iface object using its name and ensures that any other name
* doesn't retrieve a valid iface object.
*/
TEST_P(WifiChipAidlTest, GetStaIface) {
std::shared_ptr<IWifiStaIface> iface = configureChipForStaAndGetIface();
std::string iface_name = getStaIfaceName(iface);
std::shared_ptr<IWifiStaIface> retrieved_iface;
EXPECT_TRUE(wifi_chip_->getStaIface(iface_name, &retrieved_iface).isOk());
EXPECT_NE(nullptr, retrieved_iface.get());
std::string invalid_name = iface_name + "0";
std::shared_ptr<IWifiStaIface> invalid_iface;
auto status = wifi_chip_->getStaIface(invalid_name, &invalid_iface);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_EQ(nullptr, invalid_iface.get());
}
/*
* GetP2pIface
*/
TEST_P(WifiChipAidlTest, GetP2pIface) {
std::shared_ptr<IWifiP2pIface> iface = configureChipForP2pAndGetIface();
std::string iface_name = getP2pIfaceName(iface);
std::shared_ptr<IWifiP2pIface> retrieved_iface;
EXPECT_TRUE(wifi_chip_->getP2pIface(iface_name, &retrieved_iface).isOk());
EXPECT_NE(nullptr, retrieved_iface.get());
std::string invalid_name = iface_name + "0";
std::shared_ptr<IWifiP2pIface> invalid_iface;
auto status = wifi_chip_->getP2pIface(invalid_name, &invalid_iface);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_EQ(nullptr, invalid_iface.get());
}
/*
* GetApIface
*/
TEST_P(WifiChipAidlTest, GetApIface) {
std::shared_ptr<IWifiApIface> iface = configureChipForApAndGetIface();
std::string iface_name = getApIfaceName(iface);
std::shared_ptr<IWifiApIface> retrieved_iface;
EXPECT_TRUE(wifi_chip_->getApIface(iface_name, &retrieved_iface).isOk());
EXPECT_NE(nullptr, retrieved_iface.get());
std::string invalid_name = iface_name + "0";
std::shared_ptr<IWifiApIface> invalid_iface;
auto status = wifi_chip_->getApIface(invalid_name, &invalid_iface);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_EQ(nullptr, invalid_iface.get());
}
/*
* GetNanIface
*/
TEST_P(WifiChipAidlTest, GetNanIface) {
std::shared_ptr<IWifiNanIface> iface = configureChipForNanAndGetIface();
std::string iface_name = getNanIfaceName(iface);
std::shared_ptr<IWifiNanIface> retrieved_iface;
EXPECT_TRUE(wifi_chip_->getNanIface(iface_name, &retrieved_iface).isOk());
EXPECT_NE(nullptr, retrieved_iface.get());
std::string invalid_name = iface_name + "0";
std::shared_ptr<IWifiNanIface> invalid_iface;
auto status = wifi_chip_->getNanIface(invalid_name, &invalid_iface);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_EQ(nullptr, invalid_iface.get());
}
/*
* RemoveStaIface
* Configures the chip in STA mode and creates an iface. Then removes
* the iface object using the correct name and ensures that any other
* name doesn't remove the iface.
*/
TEST_P(WifiChipAidlTest, RemoveStaIface) {
std::shared_ptr<IWifiStaIface> iface = configureChipForStaAndGetIface();
std::string iface_name = getStaIfaceName(iface);
std::string invalid_name = iface_name + "0";
auto status = wifi_chip_->removeStaIface(invalid_name);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_TRUE(wifi_chip_->removeStaIface(iface_name).isOk());
// No such iface exists now, so this should return failure.
EXPECT_FALSE(wifi_chip_->removeStaIface(iface_name).isOk());
}
/*
* RemoveP2pIface
*/
TEST_P(WifiChipAidlTest, RemoveP2pIface) {
std::shared_ptr<IWifiP2pIface> iface = configureChipForP2pAndGetIface();
std::string iface_name = getP2pIfaceName(iface);
std::string invalid_name = iface_name + "0";
auto status = wifi_chip_->removeP2pIface(invalid_name);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_TRUE(wifi_chip_->removeP2pIface(iface_name).isOk());
// No such iface exists now, so this should return failure.
EXPECT_FALSE(wifi_chip_->removeP2pIface(iface_name).isOk());
}
/*
* RemoveApIface
*/
TEST_P(WifiChipAidlTest, RemoveApIface) {
std::shared_ptr<IWifiApIface> iface = configureChipForApAndGetIface();
std::string iface_name = getApIfaceName(iface);
std::string invalid_name = iface_name + "0";
auto status = wifi_chip_->removeApIface(invalid_name);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_TRUE(wifi_chip_->removeApIface(iface_name).isOk());
// No such iface exists now, so this should return failure.
EXPECT_FALSE(wifi_chip_->removeApIface(iface_name).isOk());
}
/*
* RemoveNanIface
*/
TEST_P(WifiChipAidlTest, RemoveNanIface) {
std::shared_ptr<IWifiNanIface> iface = configureChipForNanAndGetIface();
std::string iface_name = getNanIfaceName(iface);
std::string invalid_name = iface_name + "0";
auto status = wifi_chip_->removeNanIface(invalid_name);
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
EXPECT_TRUE(wifi_chip_->removeNanIface(iface_name).isOk());
// No such iface exists now, so this should return failure.
EXPECT_FALSE(wifi_chip_->removeNanIface(iface_name).isOk());
}
/*
* CreateRttController
*/
TEST_P(WifiChipAidlTest, CreateRttController) {
std::shared_ptr<IWifiStaIface> iface = configureChipForStaAndGetIface();
std::shared_ptr<IWifiRttController> rtt_controller;
auto status = wifi_chip_->createRttController(iface, &rtt_controller);
if (status.isOk()) {
EXPECT_NE(nullptr, rtt_controller.get());
} else {
EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
}
/**
* CreateBridgedApIface & RemoveIfaceInstanceFromBridgedApIface
*/
TEST_P(WifiChipAidlTest, CreateBridgedApIfaceAndremoveIfaceInstanceFromBridgedApIfaceTest) {
bool isBridgedSupport = testing::checkSubstringInCommandOutput(
"/system/bin/cmd wifi get-softap-supported-features",
"wifi_softap_bridged_ap_supported");
if (!isBridgedSupport) {
GTEST_SKIP() << "Missing Bridged AP support";
}
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
ASSERT_NE(nullptr, wifi_chip.get());
std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(wifi_chip);
ASSERT_NE(nullptr, wifi_ap_iface.get());
std::string br_name;
std::vector<std::string> instances;
EXPECT_TRUE(wifi_ap_iface->getName(&br_name).isOk());
EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
EXPECT_EQ(instances.size(), 2);
std::vector<std::string> instances_after_remove;
EXPECT_TRUE(wifi_chip->removeIfaceInstanceFromBridgedApIface(br_name, instances[0]).isOk());
EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances_after_remove).isOk());
EXPECT_EQ(instances_after_remove.size(), 1);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipAidlTest);
INSTANTIATE_TEST_SUITE_P(WifiTest, WifiChipAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
android::ProcessState::self()->startThreadPool();
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,627 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Staache 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 <vector>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/wifi/BnWifi.h>
#include <aidl/android/hardware/wifi/BnWifiNanIfaceEventCallback.h>
#include <aidl/android/hardware/wifi/NanBandIndex.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "wifi_aidl_test_utils.h"
using aidl::android::hardware::wifi::BnWifiNanIfaceEventCallback;
using aidl::android::hardware::wifi::IWifiNanIface;
using aidl::android::hardware::wifi::NanBandIndex;
using aidl::android::hardware::wifi::NanBandSpecificConfig;
using aidl::android::hardware::wifi::NanCapabilities;
using aidl::android::hardware::wifi::NanClusterEventInd;
using aidl::android::hardware::wifi::NanConfigRequest;
using aidl::android::hardware::wifi::NanConfigRequestSupplemental;
using aidl::android::hardware::wifi::NanDataPathConfirmInd;
using aidl::android::hardware::wifi::NanDataPathRequestInd;
using aidl::android::hardware::wifi::NanDataPathScheduleUpdateInd;
using aidl::android::hardware::wifi::NanDataPathSecurityType;
using aidl::android::hardware::wifi::NanEnableRequest;
using aidl::android::hardware::wifi::NanFollowupReceivedInd;
using aidl::android::hardware::wifi::NanInitiateDataPathRequest;
using aidl::android::hardware::wifi::NanMatchAlg;
using aidl::android::hardware::wifi::NanMatchInd;
using aidl::android::hardware::wifi::NanPublishRequest;
using aidl::android::hardware::wifi::NanPublishType;
using aidl::android::hardware::wifi::NanRespondToDataPathIndicationRequest;
using aidl::android::hardware::wifi::NanStatus;
using aidl::android::hardware::wifi::NanStatusCode;
using aidl::android::hardware::wifi::NanTxType;
#define TIMEOUT_PERIOD 10
class WifiNanIfaceAidlTest : public testing::TestWithParam<std::string> {
public:
void SetUp() override {
if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
GTEST_SKIP() << "Skipping this test since NAN is not supported.";
stopWifiService(getInstanceName());
wifi_nan_iface_ = getWifiNanIface(getInstanceName());
ASSERT_NE(nullptr, wifi_nan_iface_.get());
std::shared_ptr<WifiNanIfaceEventCallback> callback =
ndk::SharedRefBase::make<WifiNanIfaceEventCallback>(*this);
EXPECT_TRUE(wifi_nan_iface_->registerEventCallback(callback).isOk());
}
void TearDown() override { stopWifiService(getInstanceName()); }
// Used as a mechanism to inform the test about data/event callbacks.
inline void notify() {
std::unique_lock<std::mutex> lock(mtx_);
count_++;
cv_.notify_one();
}
enum CallbackType {
INVALID = -2,
ANY_CALLBACK = -1,
NOTIFY_CAPABILITIES_RESPONSE = 0,
NOTIFY_ENABLE_RESPONSE,
NOTIFY_CONFIG_RESPONSE,
NOTIFY_DISABLE_RESPONSE,
NOTIFY_START_PUBLISH_RESPONSE,
NOTIFY_STOP_PUBLISH_RESPONSE,
NOTIFY_START_SUBSCRIBE_RESPONSE,
NOTIFY_STOP_SUBSCRIBE_RESPONSE,
NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
NOTIFY_INITIATE_DATA_PATH_RESPONSE,
NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
EVENT_CLUSTER_EVENT,
EVENT_DISABLED,
EVENT_PUBLISH_TERMINATED,
EVENT_SUBSCRIBE_TERMINATED,
EVENT_MATCH,
EVENT_MATCH_EXPIRED,
EVENT_FOLLOWUP_RECEIVED,
EVENT_TRANSMIT_FOLLOWUP,
EVENT_DATA_PATH_REQUEST,
EVENT_DATA_PATH_CONFIRM,
EVENT_DATA_PATH_TERMINATED,
EVENT_DATA_PATH_SCHEDULE_UPDATE,
};
// Test code calls this function to wait for data/event callback.
// Must set callbackType = INVALID before calling this function.
inline std::cv_status wait(CallbackType waitForCallbackType) {
std::unique_lock<std::mutex> lock(mtx_);
EXPECT_NE(INVALID, waitForCallbackType);
std::cv_status status = std::cv_status::no_timeout;
auto now = std::chrono::system_clock::now();
while (count_ == 0) {
status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
if (status == std::cv_status::timeout) return status;
if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID &&
callback_type_ != waitForCallbackType) {
count_--;
}
}
count_--;
return status;
}
class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback {
public:
WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){};
::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override {
parent_.callback_type_ = EVENT_CLUSTER_EVENT;
parent_.nan_cluster_event_ind_ = event;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override {
parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM;
parent_.nan_data_path_confirm_ind_ = event;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override {
parent_.callback_type_ = EVENT_DATA_PATH_REQUEST;
parent_.nan_data_path_request_ind_ = event;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathScheduleUpdate(
const NanDataPathScheduleUpdateInd& event) override {
parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE;
parent_.nan_data_path_schedule_update_ind_ = event;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override {
parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED;
parent_.ndp_instance_id_ = ndpInstanceId;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override {
parent_.callback_type_ = EVENT_DISABLED;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override {
parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED;
parent_.nan_followup_received_ind_ = event;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override {
parent_.callback_type_ = EVENT_MATCH;
parent_.nan_match_ind_ = event;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override {
parent_.callback_type_ = EVENT_MATCH_EXPIRED;
parent_.session_id_ = discoverySessionId;
parent_.peer_id_ = peerId;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId,
const NanStatus& status) override {
parent_.callback_type_ = EVENT_PUBLISH_TERMINATED;
parent_.session_id_ = sessionId;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId,
const NanStatus& status) override {
parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED;
parent_.session_id_ = sessionId;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override {
parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyCapabilitiesResponse(
char16_t id, const NanStatus& status,
const NanCapabilities& capabilities) override {
parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.capabilities_ = capabilities;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id,
const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id,
const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status,
int32_t ndpInstanceId) override {
parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.ndp_instance_id_ = ndpInstanceId;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse(
char16_t id, const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status,
int8_t sessionId) override {
parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.session_id_ = sessionId;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status,
int8_t sessionId) override {
parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.session_id_ = sessionId;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id,
const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id,
const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id,
const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id,
const NanStatus& status) override {
parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.notify();
return ndk::ScopedAStatus::ok();
}
private:
WifiNanIfaceAidlTest& parent_;
};
protected:
std::shared_ptr<IWifiNanIface> wifi_nan_iface_;
CallbackType callback_type_;
uint16_t id_;
uint8_t session_id_;
uint32_t ndp_instance_id_;
uint32_t peer_id_;
NanCapabilities capabilities_;
NanClusterEventInd nan_cluster_event_ind_;
NanDataPathConfirmInd nan_data_path_confirm_ind_;
NanDataPathRequestInd nan_data_path_request_ind_;
NanDataPathScheduleUpdateInd nan_data_path_schedule_update_ind_;
NanFollowupReceivedInd nan_followup_received_ind_;
NanMatchInd nan_match_ind_;
NanStatus status_;
const char* getInstanceName() { return GetParam().c_str(); }
private:
// synchronization objects
std::mutex mtx_;
std::condition_variable cv_;
int count_ = 0;
};
/*
* FailOnIfaceInvalid
* Ensure that API calls to an interface fail with code ERROR_WIFI_IFACE_INVALID
* after wifi is disabled.
*/
TEST_P(WifiNanIfaceAidlTest, FailOnIfaceInvalid) {
stopWifiService(getInstanceName());
sleep(5); // Ensure that all chips/interfaces are invalidated.
auto status = wifi_nan_iface_->getCapabilitiesRequest(0);
ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_WIFI_IFACE_INVALID));
}
/*
* EnableRequest - Invalid Args
*/
TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
callback_type_ = INVALID;
NanEnableRequest nanEnableRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
auto status =
wifi_nan_iface_->enableRequest(inputCmdId, nanEnableRequest, nanConfigRequestSupp);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_TRUE(status.isOk());
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
}
}
/*
* ConfigRequest - Invalid Args
*/
TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
callback_type_ = INVALID;
NanConfigRequest nanConfigRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
auto status =
wifi_nan_iface_->configRequest(inputCmdId, nanConfigRequest, nanConfigRequestSupp);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_TRUE(status.isOk());
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_);
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
}
}
/*
* EnableRequest - Invalid Args in Shim Conversion
*/
TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidShimArgs) {
uint16_t inputCmdId = 10;
NanEnableRequest nanEnableRequest = {};
nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon = -15; // must be > 0
NanConfigRequestSupplemental nanConfigRequestSupp = {};
auto status =
wifi_nan_iface_->enableRequest(inputCmdId, nanEnableRequest, nanConfigRequestSupp);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
}
}
/*
* ConfigRequest - Invalid Args in Shim Conversion
*/
TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidShimArgs) {
uint16_t inputCmdId = 10;
NanConfigRequest nanConfigRequest = {};
nanConfigRequest.numberOfPublishServiceIdsInBeacon = -15; // must be > 0
NanConfigRequestSupplemental nanConfigRequestSupp = {};
auto status =
wifi_nan_iface_->configRequest(inputCmdId, nanConfigRequest, nanConfigRequestSupp);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
}
}
/*
* NotifyCapabilitiesResponse
*/
TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) {
uint16_t inputCmdId = 10;
callback_type_ = INVALID;
EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk());
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_);
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
// Check for reasonable capability values.
EXPECT_GT(capabilities_.maxConcurrentClusters, 0);
EXPECT_GT(capabilities_.maxPublishes, 0);
EXPECT_GT(capabilities_.maxSubscribes, 0);
EXPECT_EQ(capabilities_.maxServiceNameLen, 255);
EXPECT_EQ(capabilities_.maxMatchFilterLen, 255);
EXPECT_GT(capabilities_.maxTotalMatchFilterLen, 255);
EXPECT_EQ(capabilities_.maxServiceSpecificInfoLen, 255);
EXPECT_GE(capabilities_.maxExtendedServiceSpecificInfoLen, 255);
EXPECT_GT(capabilities_.maxNdiInterfaces, 0);
EXPECT_GT(capabilities_.maxNdpSessions, 0);
EXPECT_GT(capabilities_.maxAppInfoLen, 0);
EXPECT_GT(capabilities_.maxQueuedTransmitFollowupMsgs, 0);
EXPECT_GT(capabilities_.maxSubscribeInterfaceAddresses, 0);
EXPECT_NE(static_cast<int32_t>(capabilities_.supportedCipherSuites), 0);
}
/*
* StartPublishRequest
*/
TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) {
uint16_t inputCmdId = 10;
NanBandSpecificConfig config24 = {};
config24.rssiClose = 60;
config24.rssiMiddle = 70;
config24.rssiCloseProximity = 60;
config24.dwellTimeMs = 200;
config24.scanPeriodSec = 20;
config24.validDiscoveryWindowIntervalVal = false;
config24.discoveryWindowIntervalVal = 0;
NanBandSpecificConfig config5 = {};
config5.rssiClose = 60;
config5.rssiMiddle = 75;
config5.rssiCloseProximity = 60;
config5.dwellTimeMs = 200;
config5.scanPeriodSec = 20;
config5.validDiscoveryWindowIntervalVal = false;
config5.discoveryWindowIntervalVal = 0;
NanEnableRequest req = {};
req.operateInBand[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = true;
req.operateInBand[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = false;
req.hopCountMax = 2;
req.configParams.masterPref = 0;
req.configParams.disableDiscoveryAddressChangeIndication = true;
req.configParams.disableStartedClusterIndication = true;
req.configParams.disableJoinedClusterIndication = true;
req.configParams.includePublishServiceIdsInBeacon = true;
req.configParams.numberOfPublishServiceIdsInBeacon = 0;
req.configParams.includeSubscribeServiceIdsInBeacon = true;
req.configParams.numberOfSubscribeServiceIdsInBeacon = 0;
req.configParams.rssiWindowSize = 8;
req.configParams.macAddressRandomizationIntervalSec = 1800;
req.configParams.bandSpecificConfig[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] =
config24;
req.configParams.bandSpecificConfig[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] =
config5;
req.debugConfigs.validClusterIdVals = true;
req.debugConfigs.clusterIdTopRangeVal = 65535;
req.debugConfigs.clusterIdBottomRangeVal = 0;
req.debugConfigs.validIntfAddrVal = false;
req.debugConfigs.validOuiVal = false;
req.debugConfigs.ouiVal = 0;
req.debugConfigs.validRandomFactorForceVal = false;
req.debugConfigs.randomFactorForceVal = 0;
req.debugConfigs.validHopCountForceVal = false;
req.debugConfigs.hopCountForceVal = 0;
req.debugConfigs.validDiscoveryChannelVal = false;
req.debugConfigs.discoveryChannelMhzVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = 0;
req.debugConfigs.discoveryChannelMhzVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = 0;
req.debugConfigs.validUseBeaconsInBandVal = false;
req.debugConfigs.useBeaconsInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = true;
req.debugConfigs.useBeaconsInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = true;
req.debugConfigs.validUseSdfInBandVal = false;
req.debugConfigs.useSdfInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = true;
req.debugConfigs.useSdfInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = true;
NanConfigRequestSupplemental nanConfigRequestSupp = {};
nanConfigRequestSupp.discoveryBeaconIntervalMs = 20;
nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0;
nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false;
callback_type_ = INVALID;
auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_TRUE(status.isOk());
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
}
NanPublishRequest nanPublishRequest = {};
nanPublishRequest.baseConfigs.sessionId = 0;
nanPublishRequest.baseConfigs.ttlSec = 0;
nanPublishRequest.baseConfigs.discoveryWindowPeriod = 1;
nanPublishRequest.baseConfigs.discoveryCount = 0;
nanPublishRequest.baseConfigs.serviceName = {97};
nanPublishRequest.baseConfigs.discoveryMatchIndicator = NanMatchAlg::MATCH_NEVER;
nanPublishRequest.baseConfigs.useRssiThreshold = false;
nanPublishRequest.baseConfigs.disableDiscoveryTerminationIndication = false;
nanPublishRequest.baseConfigs.disableMatchExpirationIndication = true;
nanPublishRequest.baseConfigs.disableFollowupReceivedIndication = false;
nanPublishRequest.baseConfigs.securityConfig.securityType = NanDataPathSecurityType::OPEN;
nanPublishRequest.autoAcceptDataPathRequests = false;
nanPublishRequest.publishType = NanPublishType::UNSOLICITED;
nanPublishRequest.txType = NanTxType::BROADCAST;
status = wifi_nan_iface_->startPublishRequest(inputCmdId + 1, nanPublishRequest);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_TRUE(status.isOk());
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE));
ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_);
ASSERT_EQ(id_, inputCmdId + 1);
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
}
}
/*
* RespondToDataPathIndicationRequest - Invalid Args
*/
TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
callback_type_ = INVALID;
NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {};
nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong";
auto status = wifi_nan_iface_->respondToDataPathIndicationRequest(
inputCmdId, nanRespondToDataPathIndicationRequest);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_EQ(status.getServiceSpecificError(),
static_cast<int32_t>(WifiStatusCode::ERROR_INVALID_ARGS));
}
}
/*
* InitiateDataPathRequest - Invalid Args
*/
TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
callback_type_ = INVALID;
NanInitiateDataPathRequest nanInitiateDataPathRequest = {};
nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong";
auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_EQ(status.getServiceSpecificError(),
static_cast<int32_t>(WifiStatusCode::ERROR_INVALID_ARGS));
}
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceAidlTest);
INSTANTIATE_TEST_SUITE_P(WifiTest, WifiNanIfaceAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
android::ProcessState::self()->startThreadPool();
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,234 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Staache 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 <vector>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/wifi/BnWifi.h>
#include <aidl/android/hardware/wifi/BnWifiRttControllerEventCallback.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "wifi_aidl_test_utils.h"
using aidl::android::hardware::wifi::BnWifiRttControllerEventCallback;
using aidl::android::hardware::wifi::IWifiRttController;
using aidl::android::hardware::wifi::RttBw;
using aidl::android::hardware::wifi::RttCapabilities;
using aidl::android::hardware::wifi::RttConfig;
using aidl::android::hardware::wifi::RttPeerType;
using aidl::android::hardware::wifi::RttPreamble;
using aidl::android::hardware::wifi::RttResponder;
using aidl::android::hardware::wifi::RttResult;
using aidl::android::hardware::wifi::RttType;
using aidl::android::hardware::wifi::WifiChannelInfo;
using aidl::android::hardware::wifi::WifiChannelWidthInMhz;
using aidl::android::hardware::wifi::WifiStatusCode;
class WifiRttControllerAidlTest : public testing::TestWithParam<std::string> {
public:
void SetUp() override {
if (!::testing::deviceSupportsFeature("android.hardware.wifi.rtt"))
GTEST_SKIP() << "Skipping this test since RTT is not supported.";
stopWifiService(getInstanceName());
wifi_rtt_controller_ = getWifiRttController();
ASSERT_NE(nullptr, wifi_rtt_controller_.get());
// Check RTT support before we run the test.
RttCapabilities caps = {};
auto status = wifi_rtt_controller_->getCapabilities(&caps);
if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
GTEST_SKIP() << "Skipping this test since RTT is not supported.";
}
}
void TearDown() override { stopWifiService(getInstanceName()); }
protected:
std::shared_ptr<IWifiRttController> getWifiRttController() {
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
EXPECT_NE(nullptr, wifi_chip.get());
std::shared_ptr<IWifiStaIface> wifi_sta_iface = getWifiStaIface(getInstanceName());
EXPECT_NE(nullptr, wifi_sta_iface.get());
std::shared_ptr<IWifiRttController> rtt_controller;
EXPECT_TRUE(wifi_chip->createRttController(wifi_sta_iface, &rtt_controller).isOk());
EXPECT_NE(nullptr, rtt_controller.get());
return rtt_controller;
}
std::shared_ptr<IWifiRttController> wifi_rtt_controller_;
private:
const char* getInstanceName() { return GetParam().c_str(); }
};
class WifiRttControllerEventCallback : public BnWifiRttControllerEventCallback {
public:
WifiRttControllerEventCallback() = default;
::ndk::ScopedAStatus onResults(int /* cmdId */,
const std::vector<RttResult>& /* results */) override {
return ndk::ScopedAStatus::ok();
}
};
/*
* RegisterEventCallback
*
* Note: it is not feasible to test the invocation of the callback function,
* since events are triggered internally in the HAL implementation and cannot be
* triggered from the test case.
*/
TEST_P(WifiRttControllerAidlTest, RegisterEventCallback) {
std::shared_ptr<WifiRttControllerEventCallback> callback =
ndk::SharedRefBase::make<WifiRttControllerEventCallback>();
ASSERT_NE(nullptr, callback.get());
EXPECT_TRUE(wifi_rtt_controller_->registerEventCallback(callback).isOk());
}
/*
* GetCapabilities
*/
TEST_P(WifiRttControllerAidlTest, GetCapabilities) {
RttCapabilities caps = {};
EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk());
}
/*
* GetResponderInfo
*/
TEST_P(WifiRttControllerAidlTest, GetResponderInfo) {
RttResponder responder = {};
EXPECT_TRUE(wifi_rtt_controller_->getResponderInfo(&responder).isOk());
}
/*
* EnableResponder
*/
TEST_P(WifiRttControllerAidlTest, EnableResponder) {
int cmdId = 55;
WifiChannelInfo channelInfo;
channelInfo.width = WifiChannelWidthInMhz::WIDTH_80;
channelInfo.centerFreq = 5660;
channelInfo.centerFreq0 = 5660;
channelInfo.centerFreq1 = 0;
RttResponder responder = {};
EXPECT_TRUE(wifi_rtt_controller_->getResponderInfo(&responder).isOk());
EXPECT_TRUE(wifi_rtt_controller_->enableResponder(cmdId, channelInfo, 10, responder).isOk());
}
/*
* Request2SidedRangeMeasurement
* Tests the two sided ranging - 802.11mc FTM protocol.
*/
TEST_P(WifiRttControllerAidlTest, Request2SidedRangeMeasurement) {
RttCapabilities caps = {};
EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk());
if (!caps.rttFtmSupported) {
GTEST_SKIP() << "Skipping two sided RTT since driver/fw does not support";
}
RttConfig config;
config.addr = {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}};
config.type = RttType::TWO_SIDED;
config.peer = RttPeerType::AP;
config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
config.channel.centerFreq = 5180;
config.channel.centerFreq0 = 5210;
config.channel.centerFreq1 = 0;
config.bw = RttBw::BW_20MHZ;
config.preamble = RttPreamble::HT;
config.mustRequestLci = false;
config.mustRequestLcr = false;
config.burstPeriod = 0;
config.numBurst = 0;
config.numFramesPerBurst = 8;
config.numRetriesPerRttFrame = 0;
config.numRetriesPerFtmr = 0;
config.burstDuration = 9;
int cmdId = 55;
std::vector<RttConfig> configs = {config};
EXPECT_TRUE(wifi_rtt_controller_->rangeRequest(cmdId, configs).isOk());
// Sleep for 2 seconds to wait for driver/firmware to complete RTT.
sleep(2);
}
/*
* RangeRequest
*/
TEST_P(WifiRttControllerAidlTest, RangeRequest) {
RttCapabilities caps = {};
EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk());
if (!caps.rttOneSidedSupported) {
GTEST_SKIP() << "Skipping one sided RTT since driver/fw does not support";
}
// Get the highest supported preamble.
int preamble = 1;
int caps_preamble_support = static_cast<int>(caps.preambleSupport);
caps_preamble_support >>= 1;
while (caps_preamble_support != 0) {
caps_preamble_support >>= 1;
preamble <<= 1;
}
RttConfig config;
config.addr = {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}};
config.type = RttType::ONE_SIDED;
config.peer = RttPeerType::AP;
config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
config.channel.centerFreq = 5765;
config.channel.centerFreq0 = 5775;
config.channel.centerFreq1 = 0;
config.bw = RttBw::BW_80MHZ;
config.preamble = static_cast<RttPreamble>(preamble);
config.mustRequestLci = false;
config.mustRequestLcr = false;
config.burstPeriod = 0;
config.numBurst = 0;
config.numFramesPerBurst = 8;
config.numRetriesPerRttFrame = 3;
config.numRetriesPerFtmr = 3;
config.burstDuration = 9;
int cmdId = 55;
std::vector<RttConfig> configs = {config};
EXPECT_TRUE(wifi_rtt_controller_->rangeRequest(cmdId, configs).isOk());
// Sleep for 2 seconds to wait for driver/firmware to complete RTT.
sleep(2);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerAidlTest);
INSTANTIATE_TEST_SUITE_P(WifiTest, WifiRttControllerAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
android::ProcessState::self()->startThreadPool();
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Staache 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 <vector>
#include <VtsCoreUtil.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/wifi/BnWifi.h>
#include <android/binder_manager.h>
#include <android/binder_status.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "wifi_aidl_test_utils.h"
using aidl::android::hardware::wifi::IWifi;
using aidl::android::hardware::wifi::IWifiStaIface;
using aidl::android::hardware::wifi::MacAddress;
using aidl::android::hardware::wifi::Ssid;
using aidl::android::hardware::wifi::StaApfPacketFilterCapabilities;
using aidl::android::hardware::wifi::StaBackgroundScanCapabilities;
using aidl::android::hardware::wifi::StaLinkLayerStats;
using aidl::android::hardware::wifi::StaRoamingCapabilities;
using aidl::android::hardware::wifi::StaRoamingConfig;
using aidl::android::hardware::wifi::StaRoamingState;
using aidl::android::hardware::wifi::WifiBand;
using aidl::android::hardware::wifi::WifiDebugRxPacketFateReport;
using aidl::android::hardware::wifi::WifiDebugTxPacketFateReport;
using aidl::android::hardware::wifi::WifiStatusCode;
class WifiStaIfaceAidlTest : public testing::TestWithParam<std::string> {
public:
void SetUp() override {
stopWifiService(getInstanceName());
wifi_sta_iface_ = getWifiStaIface(getInstanceName());
ASSERT_NE(nullptr, wifi_sta_iface_.get());
}
void TearDown() override { stopWifiService(getInstanceName()); }
protected:
bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask expected) {
IWifiStaIface::StaIfaceCapabilityMask caps = {};
EXPECT_TRUE(wifi_sta_iface_->getCapabilities(&caps).isOk());
return static_cast<uint32_t>(caps) & static_cast<uint32_t>(expected);
}
ndk::ScopedAStatus createStaIface(std::shared_ptr<IWifiStaIface>* sta_iface) {
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
EXPECT_NE(nullptr, wifi_chip.get());
return wifi_chip->createStaIface(sta_iface);
}
std::shared_ptr<IWifiStaIface> wifi_sta_iface_;
private:
const char* getInstanceName() { return GetParam().c_str(); }
};
/*
* GetFactoryMacAddress
* Ensures that calls to getFactoryMacAddress will retrieve a non-zero MAC.
*/
TEST_P(WifiStaIfaceAidlTest, GetFactoryMacAddress) {
std::array<uint8_t, 6> mac;
EXPECT_TRUE(wifi_sta_iface_->getFactoryMacAddress(&mac).isOk());
std::array<uint8_t, 6> all_zero_mac = {0, 0, 0, 0, 0, 0};
EXPECT_NE(mac, all_zero_mac);
}
/*
* GetCapabilities
*/
TEST_P(WifiStaIfaceAidlTest, GetCapabilities) {
IWifiStaIface::StaIfaceCapabilityMask caps = {};
EXPECT_TRUE(wifi_sta_iface_->getCapabilities(&caps).isOk());
EXPECT_NE(static_cast<int32_t>(caps), 0);
}
/*
* GetApfPacketFilterCapabilities
*/
TEST_P(WifiStaIfaceAidlTest, GetApfPacketFilterCapabilities) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
GTEST_SKIP() << "APF packet filter capabilities are not supported.";
}
StaApfPacketFilterCapabilities apf_caps = {};
EXPECT_TRUE(wifi_sta_iface_->getApfPacketFilterCapabilities(&apf_caps).isOk());
}
/*
* GetBackgroundScanCapabilities
*/
TEST_P(WifiStaIfaceAidlTest, GetBackgroundScanCapabilities) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN)) {
GTEST_SKIP() << "Background scan capabilities are not supported.";
}
StaBackgroundScanCapabilities caps = {};
EXPECT_TRUE(wifi_sta_iface_->getBackgroundScanCapabilities(&caps).isOk());
}
/*
* GetValidFrequenciesForBand
* Ensures that we can retrieve valid frequencies for the 2.4 GHz band.
*/
TEST_P(WifiStaIfaceAidlTest, GetValidFrequenciesForBand) {
std::vector<int> freqs;
EXPECT_TRUE(wifi_sta_iface_->getValidFrequenciesForBand(WifiBand::BAND_24GHZ, &freqs).isOk());
EXPECT_NE(freqs.size(), 0);
}
/*
* GetLinkLayerStats
* Ensures that calls to getLinkLayerStats will retrieve a non-empty
* StaLinkLayerStats after link layer stats collection is enabled.
*/
TEST_P(WifiStaIfaceAidlTest, GetLinkLayerStats) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
GTEST_SKIP() << "Skipping this test since link layer stats are not supported.";
}
// Enable link layer stats collection.
EXPECT_TRUE(wifi_sta_iface_->enableLinkLayerStatsCollection(true).isOk());
// Retrieve link layer stats.
StaLinkLayerStats link_layer_stats = {};
EXPECT_TRUE(wifi_sta_iface_->getLinkLayerStats(&link_layer_stats).isOk());
EXPECT_GT(link_layer_stats.timeStampInMs, 0);
// Try to create a 2nd iface. If successful, it should fill the duty cycle field.
std::shared_ptr<IWifiStaIface> iface;
auto status = createStaIface(&iface);
if (status.isOk()) {
EXPECT_GT(link_layer_stats.iface.timeSliceDutyCycleInPercent, 0);
}
// Disable link layer stats collection.
EXPECT_TRUE(wifi_sta_iface_->disableLinkLayerStatsCollection().isOk());
}
/*
* SetMacAddress
* Ensures that calls to setMacAddress will return successfully.
*/
TEST_P(WifiStaIfaceAidlTest, SetMacAddress) {
std::array<uint8_t, 6> mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x41};
EXPECT_TRUE(wifi_sta_iface_->setMacAddress(mac).isOk());
}
/*
* SetScanMode
*/
TEST_P(WifiStaIfaceAidlTest, SetScanMode) {
auto status = wifi_sta_iface_->setScanMode(true);
EXPECT_TRUE(status.isOk() || checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
status = wifi_sta_iface_->setScanMode(false);
EXPECT_TRUE(status.isOk() || checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
}
/*
* LinkLayerStatsCollection
*/
TEST_P(WifiStaIfaceAidlTest, LinkLayerStatsCollection) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
GTEST_SKIP() << "Link layer stats collection is not supported.";
}
// Enable link layer stats collection.
EXPECT_TRUE(wifi_sta_iface_->enableLinkLayerStatsCollection(true).isOk());
// Retrieve link layer stats.
StaLinkLayerStats link_layer_stats = {};
EXPECT_TRUE(wifi_sta_iface_->getLinkLayerStats(&link_layer_stats).isOk());
// Disable link layer stats collection.
EXPECT_TRUE(wifi_sta_iface_->disableLinkLayerStatsCollection().isOk());
}
/*
* RSSIMonitoring
* Ensures that calls to startRssiMonitoring and stopRssiMonitoring will fail
* if the device is not connected to an AP.
*/
TEST_P(WifiStaIfaceAidlTest, RSSIMonitoring) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR)) {
GTEST_SKIP() << "RSSI monitoring is not supported.";
}
const int cmd = 1;
const int maxRssi = -50;
const int minRssi = -90;
// Expected to fail because device is not connected to an AP.
EXPECT_FALSE(wifi_sta_iface_->startRssiMonitoring(cmd, maxRssi, minRssi).isOk());
EXPECT_FALSE(wifi_sta_iface_->stopRssiMonitoring(cmd).isOk());
}
/*
* RoamingControl
*/
TEST_P(WifiStaIfaceAidlTest, RoamingControl) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING)) {
GTEST_SKIP() << "Roaming control is not supported.";
}
// Retrieve roaming capabilities.
StaRoamingCapabilities caps = {};
EXPECT_TRUE(wifi_sta_iface_->getRoamingCapabilities(&caps).isOk());
// Set up roaming configuration based on roaming capabilities.
StaRoamingConfig roaming_config = {};
if (caps.maxBlocklistSize > 0) {
MacAddress block_list_entry;
block_list_entry.data = std::array<uint8_t, 6>{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}};
roaming_config.bssidBlocklist = {block_list_entry};
}
if (caps.maxAllowlistSize > 0) {
Ssid allow_list_entry = {};
allow_list_entry.data = std::array<uint8_t, 32>{{0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}};
roaming_config.ssidAllowlist = {allow_list_entry};
}
// Configure roaming.
EXPECT_TRUE(wifi_sta_iface_->configureRoaming(roaming_config).isOk());
// Enable roaming.
EXPECT_TRUE(wifi_sta_iface_->setRoamingState(StaRoamingState::ENABLED).isOk());
}
/*
* EnableNDOffload
*/
TEST_P(WifiStaIfaceAidlTest, EnableNDOffload) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
GTEST_SKIP() << "ND offload is not supported.";
}
EXPECT_TRUE(wifi_sta_iface_->enableNdOffload(true).isOk());
}
/*
* PacketFateMonitoring
*/
TEST_P(WifiStaIfaceAidlTest, PacketFateMonitoring) {
if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
GTEST_SKIP() << "Packet fate monitoring is not supported.";
}
// Start packet fate monitoring.
EXPECT_TRUE(wifi_sta_iface_->startDebugPacketFateMonitoring().isOk());
// Retrieve packets.
std::vector<WifiDebugRxPacketFateReport> rx_reports;
std::vector<WifiDebugTxPacketFateReport> tx_reports;
EXPECT_TRUE(wifi_sta_iface_->getDebugRxPacketFates(&rx_reports).isOk());
EXPECT_TRUE(wifi_sta_iface_->getDebugTxPacketFates(&tx_reports).isOk());
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceAidlTest);
INSTANTIATE_TEST_SUITE_P(WifiTest, WifiStaIfaceAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
android::PrintInstanceNameToString);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
android::ProcessState::self()->startThreadPool();
return RUN_ALL_TESTS();
}