diff --git a/wifi/1.2/default/Android.mk b/wifi/1.2/default/Android.mk index b242cfc4e0..95414bc743 100644 --- a/wifi/1.2/default/Android.mk +++ b/wifi/1.2/default/Android.mk @@ -13,21 +13,27 @@ # limitations under the License. LOCAL_PATH := $(call my-dir) +### +### android.hardware.wifi static library +### include $(CLEAR_VARS) -LOCAL_MODULE := android.hardware.wifi@1.0-service +LOCAL_MODULE := android.hardware.wifi@1.0-service-lib LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_CPPFLAGS := -Wall -Werror -Wextra ifdef WIFI_HIDL_FEATURE_AWARE LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE endif +ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE +LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE +endif LOCAL_SRC_FILES := \ hidl_struct_util.cpp \ hidl_sync_util.cpp \ - service.cpp \ wifi.cpp \ wifi_ap_iface.cpp \ wifi_chip.cpp \ + wifi_feature_flags.cpp \ wifi_legacy_hal.cpp \ wifi_legacy_hal_stubs.cpp \ wifi_mode_controller.cpp \ @@ -49,5 +55,64 @@ LOCAL_SHARED_LIBRARIES := \ android.hardware.wifi@1.0 \ android.hardware.wifi@1.1 \ android.hardware.wifi@1.2 +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) +include $(BUILD_STATIC_LIBRARY) + +### +### android.hardware.wifi daemon +### +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.wifi@1.0-service +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_CPPFLAGS := -Wall -Werror -Wextra +LOCAL_SRC_FILES := \ + service.cpp +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libhidlbase \ + libhidltransport \ + liblog \ + libnl \ + libutils \ + libwifi-hal \ + libwifi-system-iface \ + android.hardware.wifi@1.0 \ + android.hardware.wifi@1.1 \ + android.hardware.wifi@1.2 +LOCAL_STATIC_LIBRARIES := \ + android.hardware.wifi@1.0-service-lib LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc include $(BUILD_EXECUTABLE) + +### +### android.hardware.wifi unit tests. +### +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.wifi@1.0-service-tests +LOCAL_PROPRIETARY_MODULE := true +LOCAL_SRC_FILES := \ + tests/main.cpp \ + tests/mock_wifi_feature_flags.cpp \ + tests/mock_wifi_legacy_hal.cpp \ + tests/mock_wifi_mode_controller.cpp \ + tests/wifi_chip_unit_tests.cpp +LOCAL_STATIC_LIBRARIES := \ + libgmock \ + libgtest \ + android.hardware.wifi@1.0-service-lib +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libhidlbase \ + libhidltransport \ + liblog \ + libnl \ + libutils \ + libwifi-hal \ + libwifi-system-iface \ + android.hardware.wifi@1.0 \ + android.hardware.wifi@1.1 \ + android.hardware.wifi@1.2 +include $(BUILD_NATIVE_TEST) diff --git a/wifi/1.2/default/service.cpp b/wifi/1.2/default/service.cpp index 6297cf2158..01d22bd881 100644 --- a/wifi/1.2/default/service.cpp +++ b/wifi/1.2/default/service.cpp @@ -20,9 +20,17 @@ #include #include "wifi.h" +#include "wifi_feature_flags.h" +#include "wifi_legacy_hal.h" +#include "wifi_mode_controller.h" using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; +using android::hardware::wifi::V1_2::implementation::feature_flags:: + WifiFeatureFlags; +using android::hardware::wifi::V1_2::implementation::legacy_hal::WifiLegacyHal; +using android::hardware::wifi::V1_2::implementation::mode_controller:: + WifiModeController; int main(int /*argc*/, char** argv) { android::base::InitLogging( @@ -33,7 +41,10 @@ int main(int /*argc*/, char** argv) { // Setup hwbinder service android::sp service = - new android::hardware::wifi::V1_2::implementation::Wifi(); + new android::hardware::wifi::V1_2::implementation::Wifi( + std::make_shared(), + std::make_shared(), + std::make_shared()); CHECK_EQ(service->registerAsService(), android::NO_ERROR) << "Failed to register wifi HAL"; diff --git a/wifi/1.2/default/tests/main.cpp b/wifi/1.2/default/tests/main.cpp new file mode 100644 index 0000000000..9aac837242 --- /dev/null +++ b/wifi/1.2/default/tests/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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 +#include + +#include + +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(); +} diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp new file mode 100644 index 0000000000..8d0b1921c2 --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 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 + +#include "mock_wifi_feature_flags.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace feature_flags { + +MockWifiFeatureFlags::MockWifiFeatureFlags() {} + +} // namespace feature_flags +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.h b/wifi/1.2/default/tests/mock_wifi_feature_flags.h new file mode 100644 index 0000000000..8cf1d4b258 --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_feature_flags.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 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 + +#include "wifi_feature_flags.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace feature_flags { + +class MockWifiFeatureFlags : public WifiFeatureFlags { + public: + MockWifiFeatureFlags(); + + MOCK_METHOD0(isAwareSupported, bool()); + MOCK_METHOD0(isDualInterfaceSupported, bool()); +}; + +} // namespace feature_flags +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // MOCK_WIFI_FEATURE_FLAGS_H_ diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp new file mode 100644 index 0000000000..8381ddef4e --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 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 +#include +#include + +#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 +#include "mock_wifi_legacy_hal.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace legacy_hal { + +MockWifiLegacyHal::MockWifiLegacyHal() : WifiLegacyHal() {} +} // namespace legacy_hal +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.h b/wifi/1.2/default/tests/mock_wifi_legacy_hal.h new file mode 100644 index 0000000000..8e1696e10c --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_legacy_hal.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 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 + +#include "wifi_legacy_hal.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace legacy_hal { + +class MockWifiLegacyHal : public WifiLegacyHal { + public: + MockWifiLegacyHal(); + MOCK_METHOD0(initialize, wifi_error()); + MOCK_METHOD0(start, wifi_error()); + MOCK_METHOD2(stop, wifi_error(std::unique_lock*, + const std::function&)); + MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool)); + 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&)); +}; +} // namespace legacy_hal +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // MOCK_WIFI_LEGACY_HAL_H_ diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp new file mode 100644 index 0000000000..461a581a22 --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 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 +#include +#include + +#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 +#include "mock_wifi_mode_controller.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace mode_controller { + +MockWifiModeController::MockWifiModeController() : WifiModeController() {} +} // namespace mode_controller +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.h b/wifi/1.2/default/tests/mock_wifi_mode_controller.h new file mode 100644 index 0000000000..50c3e35bbc --- /dev/null +++ b/wifi/1.2/default/tests/mock_wifi_mode_controller.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 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 + +#include "wifi_mode_controller.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +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 implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // MOCK_WIFI_MODE_CONTROLLER_H_ diff --git a/wifi/1.2/default/tests/runtests.sh b/wifi/1.2/default/tests/runtests.sh new file mode 100755 index 0000000000..966a6a751c --- /dev/null +++ b/wifi/1.2/default/tests/runtests.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +# Copyright(C) 2017 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 + +echo "Running tests" +set -e # fail early + +#NOTE We can't actually run these commands, since they rely on functions added by +#build / envsetup.sh to the bash shell environment. +echo "+ mmma -j32 $ANDROID_BUILD_TOP/" +make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \ + MODULES-IN-hardware-interfaces-wifi-1.2-default + +set -x # print commands + +adb wait-for-device +adb root +adb wait-for-device + +#'disable-verity' will appear in 'adb remount' output if +#dm - verity is enabled and needs to be disabled. +if adb remount | grep 'disable-verity'; then + adb disable-verity + adb reboot + adb wait-for-device + adb root + adb wait-for-device + adb remount +fi + +adb sync + +adb shell /data/nativetest/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp new file mode 100644 index 0000000000..f73869bc53 --- /dev/null +++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2017, 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 +#include +#include + +#undef NAN // This is weird, NAN is defined in bionic/libc/include/math.h:38 +#include "wifi_chip.h" + +#include "mock_wifi_feature_flags.h" +#include "mock_wifi_legacy_hal.h" +#include "mock_wifi_mode_controller.h" + +using testing::NiceMock; +using testing::Return; +using testing::Test; + +namespace { +using android::hardware::wifi::V1_0::ChipId; + +constexpr ChipId kFakeChipId = 5; +} // namespace + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { + +class WifiChipTest : public Test { + protected: + void setupV1IfaceCombination() { + EXPECT_CALL(*feature_flags_, isAwareSupported()) + .WillRepeatedly(testing::Return(false)); + EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) + .WillRepeatedly(testing::Return(false)); + } + + void setupV1_AwareIfaceCombination() { + EXPECT_CALL(*feature_flags_, isAwareSupported()) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) + .WillRepeatedly(testing::Return(false)); + } + + void setupV2_AwareIfaceCombination() { + EXPECT_CALL(*feature_flags_, isAwareSupported()) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*feature_flags_, isDualInterfaceSupported()) + .WillRepeatedly(testing::Return(true)); + } + + void assertNumberOfModes(uint32_t num_modes) { + chip_->getAvailableModes( + [num_modes](const WifiStatus& status, + const std::vector& modes) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + // V2_Aware has 1 mode of operation. + ASSERT_EQ(num_modes, modes.size()); + }); + } + + void findModeAndConfigureForIfaceType(const IfaceType& type) { + // This should be aligned with kInvalidModeId in wifi_chip.cpp. + ChipModeId mode_id = UINT32_MAX; + chip_->getAvailableModes( + [&mode_id, &type](const WifiStatus& status, + const std::vector& modes) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + 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(UINT32_MAX, mode_id); + + chip_->configureChip(mode_id, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } + + // Returns an empty string on error. + std::string createIface(const IfaceType& type) { + std::string iface_name; + if (type == IfaceType::AP) { + chip_->createApIface([&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } else if (type == IfaceType::NAN) { + chip_->createNanIface( + [&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } else if (type == IfaceType::P2P) { + chip_->createP2pIface( + [&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } else if (type == IfaceType::STA) { + chip_->createStaIface( + [&iface_name](const WifiStatus& status, + const sp& iface) { + if (WifiStatusCode::SUCCESS == status.code) { + ASSERT_NE(iface.get(), nullptr); + iface->getName([&iface_name](const WifiStatus& status, + const hidl_string& name) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + iface_name = name.c_str(); + }); + } + }); + } + return iface_name; + } + + void removeIface(const IfaceType& type, const std::string& iface_name) { + if (type == IfaceType::AP) { + chip_->removeApIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } else if (type == IfaceType::NAN) { + chip_->removeNanIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } else if (type == IfaceType::P2P) { + chip_->removeP2pIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } else if (type == IfaceType::STA) { + chip_->removeStaIface(iface_name, [](const WifiStatus& status) { + ASSERT_EQ(WifiStatusCode::SUCCESS, status.code); + }); + } + } + + public: + void SetUp() override { + chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_, + feature_flags_); + + EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_)) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*legacy_hal_, start()) + .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS)); + } + + private: + sp chip_; + ChipId chip_id_ = kFakeChipId; + std::shared_ptr> legacy_hal_{ + new NiceMock}; + std::shared_ptr> + mode_controller_{new NiceMock}; + std::shared_ptr> + feature_flags_{new NiceMock}; +}; + +////////// 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(2u); + } +}; + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::NAN).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(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaP2PNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, + StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto nan_iface_name = createIface(IfaceType::NAN); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +////////// 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(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaStaAp_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaAp_AfterStaRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto sta_iface_name = createIface(IfaceType::STA); + ASSERT_FALSE(sta_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::AP).empty()); + + // After removing STA iface, AP iface creation should succeed. + removeIface(IfaceType::STA, sta_iface_name); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaSta_AfterApRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto ap_iface_name = createIface(IfaceType::AP); + ASSERT_FALSE(ap_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::STA).empty()); + + // After removing AP iface, STA iface creation should succeed. + removeIface(IfaceType::AP, ap_iface_name); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto nan_iface_name = createIface(IfaceType::NAN); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) { + findModeAndConfigureForIfaceType(IfaceType::AP); + ASSERT_FALSE(createIface(IfaceType::AP).empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto p2p_iface_name = createIface(IfaceType::P2P); + ASSERT_FALSE(p2p_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::NAN).empty()); + + // After removing P2P iface, NAN iface creation should succeed. + removeIface(IfaceType::P2P, p2p_iface_name); + ASSERT_FALSE(createIface(IfaceType::NAN).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) { + findModeAndConfigureForIfaceType(IfaceType::STA); + ASSERT_FALSE(createIface(IfaceType::STA).empty()); + const auto nan_iface_name = createIface(IfaceType::NAN); + ASSERT_FALSE(nan_iface_name.empty()); + ASSERT_TRUE(createIface(IfaceType::P2P).empty()); + + // After removing NAN iface, P2P iface creation should succeed. + removeIface(IfaceType::NAN, nan_iface_name); + ASSERT_FALSE(createIface(IfaceType::P2P).empty()); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaSta_EnsureDifferentIfaceNames) { + findModeAndConfigureForIfaceType(IfaceType::AP); + const auto sta1_iface_name = createIface(IfaceType::STA); + const auto sta2_iface_name = createIface(IfaceType::STA); + ASSERT_FALSE(sta1_iface_name.empty()); + ASSERT_FALSE(sta2_iface_name.empty()); + ASSERT_NE(sta1_iface_name, sta2_iface_name); +} + +TEST_F(WifiChipV2_AwareIfaceCombinationTest, + CreateStaAp_EnsureDifferentIfaceNames) { + findModeAndConfigureForIfaceType(IfaceType::AP); + const auto sta_iface_name = createIface(IfaceType::STA); + const auto 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); +} +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.2/default/wifi.cpp index a2d8f9f1ef..06f5058891 100644 --- a/wifi/1.2/default/wifi.cpp +++ b/wifi/1.2/default/wifi.cpp @@ -33,9 +33,13 @@ namespace implementation { using hidl_return_util::validateAndCall; using hidl_return_util::validateAndCallWithLock; -Wifi::Wifi() - : legacy_hal_(new legacy_hal::WifiLegacyHal()), - mode_controller_(new mode_controller::WifiModeController()), +Wifi::Wifi( + const std::shared_ptr legacy_hal, + const std::shared_ptr mode_controller, + const std::shared_ptr feature_flags) + : legacy_hal_(legacy_hal), + mode_controller_(mode_controller), + feature_flags_(feature_flags), run_state_(RunState::STOPPED) {} bool Wifi::isValid() { @@ -88,10 +92,11 @@ WifiStatus Wifi::startInternal() { return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping"); } - WifiStatus wifi_status = initializeLegacyHal(); + WifiStatus wifi_status = initializeModeControllerAndLegacyHal(); if (wifi_status.code == WifiStatusCode::SUCCESS) { // Create the chip instance once the HAL is started. - chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_); + chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_, + feature_flags_); run_state_ = RunState::STARTED; for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onStart().isOk()) { @@ -161,7 +166,11 @@ std::pair> Wifi::getChipInternal(ChipId chip_id) { return {createWifiStatus(WifiStatusCode::SUCCESS), chip_}; } -WifiStatus Wifi::initializeLegacyHal() { +WifiStatus Wifi::initializeModeControllerAndLegacyHal() { + if (!mode_controller_->initialize()) { + LOG(ERROR) << "Failed to initialize firmware mode controller"; + return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN); + } legacy_hal::wifi_error legacy_status = legacy_hal_->initialize(); if (legacy_status != legacy_hal::WIFI_SUCCESS) { LOG(ERROR) << "Failed to initialize legacy HAL: " diff --git a/wifi/1.2/default/wifi.h b/wifi/1.2/default/wifi.h index 114d7745a8..440c3c7984 100644 --- a/wifi/1.2/default/wifi.h +++ b/wifi/1.2/default/wifi.h @@ -25,6 +25,7 @@ #include "hidl_callback_util.h" #include "wifi_chip.h" +#include "wifi_feature_flags.h" #include "wifi_legacy_hal.h" #include "wifi_mode_controller.h" @@ -39,7 +40,10 @@ namespace implementation { */ class Wifi : public V1_2::IWifi { public: - Wifi(); + Wifi(const std::shared_ptr legacy_hal, + const std::shared_ptr + mode_controller, + const std::shared_ptr feature_flags); bool isValid(); @@ -64,7 +68,7 @@ class Wifi : public V1_2::IWifi { std::pair> getChipIdsInternal(); std::pair> getChipInternal(ChipId chip_id); - WifiStatus initializeLegacyHal(); + WifiStatus initializeModeControllerAndLegacyHal(); WifiStatus stopLegacyHalAndDeinitializeModeController( std::unique_lock* lock); @@ -72,6 +76,7 @@ class Wifi : public V1_2::IWifi { // and shared with all the child HIDL interface objects. std::shared_ptr legacy_hal_; std::shared_ptr mode_controller_; + std::shared_ptr feature_flags_; RunState run_state_; sp chip_; hidl_callback_util::HidlCallbackHandler diff --git a/wifi/1.2/default/wifi_ap_iface.cpp b/wifi/1.2/default/wifi_ap_iface.cpp index 284f9b9774..92b7b48d98 100644 --- a/wifi/1.2/default/wifi_ap_iface.cpp +++ b/wifi/1.2/default/wifi_ap_iface.cpp @@ -40,6 +40,8 @@ void WifiApIface::invalidate() { bool WifiApIface::isValid() { return is_valid_; } +std::string WifiApIface::getName() { return ifname_; } + Return WifiApIface::getName(getName_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiApIface::getNameInternal, hidl_status_cb); diff --git a/wifi/1.2/default/wifi_ap_iface.h b/wifi/1.2/default/wifi_ap_iface.h index 6375121c80..5363ec2586 100644 --- a/wifi/1.2/default/wifi_ap_iface.h +++ b/wifi/1.2/default/wifi_ap_iface.h @@ -39,6 +39,7 @@ class WifiApIface : public V1_0::IWifiApIface { // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override; diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp index 4e2191d10b..adba054e2d 100644 --- a/wifi/1.2/default/wifi_chip.cpp +++ b/wifi/1.2/default/wifi_chip.cpp @@ -20,27 +20,59 @@ #include "hidl_return_util.h" #include "hidl_struct_util.h" #include "wifi_chip.h" -#include "wifi_feature_flags.h" #include "wifi_status_util.h" namespace { using android::hardware::hidl_string; using android::hardware::hidl_vec; using android::hardware::wifi::V1_0::ChipModeId; -using android::hardware::wifi::V1_0::IWifiChip; using android::hardware::wifi::V1_0::IfaceType; +using android::hardware::wifi::V1_0::IWifiChip; using android::sp; -constexpr ChipModeId kStaChipModeId = 0; -constexpr ChipModeId kApChipModeId = 1; constexpr ChipModeId kInvalidModeId = UINT32_MAX; +// These mode ID's should be unique (even across combo versions). Refer to +// handleChipConfiguration() for it's usage. +// Mode ID's for V1 +constexpr ChipModeId kV1StaChipModeId = 0; +constexpr ChipModeId kV1ApChipModeId = 1; +// Mode ID for V2 +constexpr ChipModeId kV2ChipModeId = 2; template -void invalidateAndClear(sp& iface) { - if (iface.get()) { +void invalidateAndClear(std::vector>& ifaces, sp iface) { + iface->invalidate(); + ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), + ifaces.end()); +} + +template +void invalidateAndClearAll(std::vector>& ifaces) { + for (const auto& iface : ifaces) { iface->invalidate(); - iface.clear(); } + ifaces.clear(); +} + +template +std::vector getNames(std::vector>& ifaces) { + std::vector names; + for (const auto& iface : ifaces) { + names.emplace_back(iface->getName()); + } + return names; +} + +template +sp findUsingName(std::vector>& ifaces, + const std::string& name) { + std::vector names; + for (const auto& iface : ifaces) { + if (name == iface->getName()) { + return iface; + } + } + return nullptr; } std::string getWlan0IfaceName() { @@ -49,13 +81,11 @@ std::string getWlan0IfaceName() { return buffer.data(); } -/** Not used yet. std::string getWlan1IfaceName() { - std::array buffer; - property_get("wifi.concurrent.interface", buffer.data(), "wlan1"); - return buffer.data(); + std::array buffer; + property_get("wifi.concurrent.interface", buffer.data(), "wlan1"); + return buffer.data(); } -*/ std::string getP2pIfaceName() { std::array buffer; @@ -75,13 +105,17 @@ using hidl_return_util::validateAndCallWithLock; WifiChip::WifiChip( ChipId chip_id, const std::weak_ptr legacy_hal, - const std::weak_ptr mode_controller) + const std::weak_ptr mode_controller, + const std::weak_ptr feature_flags) : chip_id_(chip_id), legacy_hal_(legacy_hal), mode_controller_(mode_controller), + feature_flags_(feature_flags), is_valid_(true), current_mode_id_(kInvalidModeId), - debug_ring_buffer_cb_registered_(false) {} + debug_ring_buffer_cb_registered_(false) { + populateModes(); +} void WifiChip::invalidate() { invalidateAndRemoveAllIfaces(); @@ -317,10 +351,10 @@ Return WifiChip::resetTxPowerScenario( } void WifiChip::invalidateAndRemoveAllIfaces() { - invalidateAndClear(ap_iface_); - invalidateAndClear(nan_iface_); - invalidateAndClear(p2p_iface_); - invalidateAndClear(sta_iface_); + invalidateAndClearAll(ap_ifaces_); + invalidateAndClearAll(nan_ifaces_); + invalidateAndClearAll(p2p_ifaces_); + invalidateAndClearAll(sta_ifaces_); // Since all the ifaces are invalid now, all RTT controller objects // using those ifaces also need to be invalidated. for (const auto& rtt : rtt_controllers_) { @@ -365,43 +399,13 @@ std::pair WifiChip::getCapabilitiesInternal() { std::pair> WifiChip::getAvailableModesInternal() { - // The chip combination supported for current devices is fixed for now with - // 2 separate modes of operation: - // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN iface operations - // concurrently [NAN conditional on wifiHidlFeatureAware] - // Mode 2 (AP mode): Will support 1 AP iface operations. - // TODO (b/32997844): Read this from some device specific flags in the - // makefile. - // STA mode iface combinations. - const IWifiChip::ChipIfaceCombinationLimit - sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; - IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2; - if (WifiFeatureFlags::wifiHidlFeatureAware) { - sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN}, - 1}; - } else { - sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 1}; - } - const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = { - {sta_chip_iface_combination_limit_1, - sta_chip_iface_combination_limit_2}}; - const IWifiChip::ChipMode sta_chip_mode = {kStaChipModeId, - {sta_chip_iface_combination}}; - // AP mode iface combinations. - const IWifiChip::ChipIfaceCombinationLimit ap_chip_iface_combination_limit = - {{IfaceType::AP}, 1}; - const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = { - {ap_chip_iface_combination_limit}}; - const IWifiChip::ChipMode ap_chip_mode = {kApChipModeId, - {ap_chip_iface_combination}}; - return {createWifiStatus(WifiStatusCode::SUCCESS), - {sta_chip_mode, ap_chip_mode}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), modes_}; } WifiStatus WifiChip::configureChipInternal( /* NONNULL */ std::unique_lock* lock, ChipModeId mode_id) { - if (mode_id != kStaChipModeId && mode_id != kApChipModeId) { + if (!isValidModeId(mode_id)) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } if (mode_id == current_mode_id_) { @@ -429,7 +433,7 @@ WifiStatus WifiChip::configureChipInternal( } std::pair WifiChip::getModeInternal() { - if (current_mode_id_ == kInvalidModeId) { + if (!isValidModeId(current_mode_id_)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), current_mode_id_}; } @@ -497,40 +501,43 @@ WifiChip::requestFirmwareDebugDumpInternal() { } std::pair> WifiChip::createApIfaceInternal() { - if (current_mode_id_ != kApChipModeId || ap_iface_.get()) { + if (!canCurrentModeSupportIfaceOfType(IfaceType::AP)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } - std::string ifname = getWlan0IfaceName(); - ap_iface_ = new WifiApIface(ifname, legacy_hal_); + std::string ifname = allocateApOrStaIfaceName(); + sp iface = new WifiApIface(ifname, legacy_hal_); + ap_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; } } - return {createWifiStatus(WifiStatusCode::SUCCESS), ap_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> WifiChip::getApIfaceNamesInternal() { - if (!ap_iface_.get()) { + if (ap_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getWlan0IfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)}; } std::pair> WifiChip::getApIfaceInternal( const std::string& ifname) { - if (!ap_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(ap_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), ap_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { - if (!ap_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(ap_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(ap_iface_); + invalidateAndClear(ap_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; @@ -540,46 +547,44 @@ WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) { } std::pair> WifiChip::createNanIfaceInternal() { - // Only 1 of NAN or P2P iface can be active at a time. - if (WifiFeatureFlags::wifiHidlFeatureAware) { - if (current_mode_id_ != kStaChipModeId || nan_iface_.get() || - p2p_iface_.get()) { - return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; - } - std::string ifname = getWlan0IfaceName(); - nan_iface_ = new WifiNanIface(ifname, legacy_hal_); - for (const auto& callback : event_cb_handler_.getCallbacks()) { - if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) { - LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; - } - } - return {createWifiStatus(WifiStatusCode::SUCCESS), nan_iface_}; - } else { + if (!canCurrentModeSupportIfaceOfType(IfaceType::NAN)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } + // These are still assumed to be based on wlan0. + std::string ifname = getWlan0IfaceName(); + sp iface = new WifiNanIface(ifname, legacy_hal_); + nan_ifaces_.push_back(iface); + for (const auto& callback : event_cb_handler_.getCallbacks()) { + if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) { + LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; + } + } + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> WifiChip::getNanIfaceNamesInternal() { - if (!nan_iface_.get()) { + if (nan_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getWlan0IfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)}; } std::pair> WifiChip::getNanIfaceInternal( const std::string& ifname) { - if (!nan_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(nan_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), nan_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) { - if (!nan_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(nan_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(nan_iface_); + invalidateAndClear(nan_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; @@ -589,42 +594,43 @@ WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) { } std::pair> WifiChip::createP2pIfaceInternal() { - // Only 1 of NAN or P2P iface can be active at a time. - if (current_mode_id_ != kStaChipModeId || p2p_iface_.get() || - nan_iface_.get()) { + if (!canCurrentModeSupportIfaceOfType(IfaceType::P2P)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } std::string ifname = getP2pIfaceName(); - p2p_iface_ = new WifiP2pIface(ifname, legacy_hal_); + sp iface = new WifiP2pIface(ifname, legacy_hal_); + p2p_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; } } - return {createWifiStatus(WifiStatusCode::SUCCESS), p2p_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> WifiChip::getP2pIfaceNamesInternal() { - if (!p2p_iface_.get()) { + if (p2p_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getP2pIfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)}; } std::pair> WifiChip::getP2pIfaceInternal( const std::string& ifname) { - if (!p2p_iface_.get() || (ifname != getP2pIfaceName())) { + const auto iface = findUsingName(p2p_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), p2p_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { - if (!p2p_iface_.get() || (ifname != getP2pIfaceName())) { + const auto iface = findUsingName(p2p_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(p2p_iface_); + invalidateAndClear(p2p_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; @@ -634,40 +640,43 @@ WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) { } std::pair> WifiChip::createStaIfaceInternal() { - if (current_mode_id_ != kStaChipModeId || sta_iface_.get()) { + if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) { return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}}; } - std::string ifname = getWlan0IfaceName(); - sta_iface_ = new WifiStaIface(ifname, legacy_hal_); + std::string ifname = allocateApOrStaIfaceName(); + sp iface = new WifiStaIface(ifname, legacy_hal_); + sta_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceAdded callback"; } } - return {createWifiStatus(WifiStatusCode::SUCCESS), sta_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } std::pair> WifiChip::getStaIfaceNamesInternal() { - if (!sta_iface_.get()) { + if (sta_ifaces_.empty()) { return {createWifiStatus(WifiStatusCode::SUCCESS), {}}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), {getWlan0IfaceName()}}; + return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)}; } std::pair> WifiChip::getStaIfaceInternal( const std::string& ifname) { - if (!sta_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(sta_ifaces_, ifname); + if (!iface.get()) { return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr}; } - return {createWifiStatus(WifiStatusCode::SUCCESS), sta_iface_}; + return {createWifiStatus(WifiStatusCode::SUCCESS), iface}; } WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) { - if (!sta_iface_.get() || (ifname != getWlan0IfaceName())) { + const auto iface = findUsingName(sta_ifaces_, ifname); + if (!iface.get()) { return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS); } - invalidateAndClear(sta_iface_); + invalidateAndClear(sta_ifaces_, iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) { LOG(ERROR) << "Failed to invoke onIfaceRemoved callback"; @@ -801,7 +810,7 @@ WifiStatus WifiChip::handleChipConfiguration( ChipModeId mode_id) { // If the chip is already configured in a different mode, stop // the legacy HAL and then start it after firmware mode change. - if (current_mode_id_ != kInvalidModeId) { + if (isValidModeId(current_mode_id_)) { LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_ << " to mode " << mode_id; invalidateAndRemoveAllIfaces(); @@ -813,10 +822,11 @@ WifiStatus WifiChip::handleChipConfiguration( return createWifiStatusFromLegacyError(legacy_status); } } - bool success; - if (mode_id == kStaChipModeId) { + // Firmware mode change not needed for V2 devices. + bool success = true; + if (mode_id == kV1StaChipModeId) { success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA); - } else { + } else if (mode_id == kV1ApChipModeId) { success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP); } if (!success) { @@ -871,6 +881,204 @@ WifiStatus WifiChip::registerDebugRingBufferCallback() { return createWifiStatusFromLegacyError(legacy_status); } +void WifiChip::populateModes() { + // The chip combination supported for current devices is fixed. + // They can be one of the following based on device features: + // a) 2 separate modes of operation with 1 interface combination each: + // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN(optional) + // concurrent iface operations. + // Mode 2 (AP mode): Will support 1 AP iface operation. + // + // b) 1 mode of operation with 2 interface combinations + // (conditional on isDualInterfaceSupported()): + // Interface Combination 1: Will support 1 STA and 1 P2P or NAN(optional) + // concurrent iface operations. + // Interface Combination 2: Will support 1 STA and 1 STA or AP concurrent + // iface operations. + // If Aware is enabled (conditional on isAwareSupported()), the iface + // combination will be modified to support either P2P or NAN in place of + // just P2P. + if (feature_flags_.lock()->isDualInterfaceSupported()) { + // V2 Iface combinations for Mode Id = 2. + const IWifiChip::ChipIfaceCombinationLimit + chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; + const IWifiChip::ChipIfaceCombinationLimit + chip_iface_combination_limit_2 = {{IfaceType::STA, IfaceType::AP}, + 1}; + IWifiChip::ChipIfaceCombinationLimit chip_iface_combination_limit_3; + if (feature_flags_.lock()->isAwareSupported()) { + chip_iface_combination_limit_3 = {{IfaceType::P2P, IfaceType::NAN}, + 1}; + } else { + chip_iface_combination_limit_3 = {{IfaceType::P2P}, 1}; + } + const IWifiChip::ChipIfaceCombination chip_iface_combination_1 = { + {chip_iface_combination_limit_1, chip_iface_combination_limit_2}}; + const IWifiChip::ChipIfaceCombination chip_iface_combination_2 = { + {chip_iface_combination_limit_1, chip_iface_combination_limit_3}}; + const IWifiChip::ChipMode chip_mode = { + kV2ChipModeId, + {chip_iface_combination_1, chip_iface_combination_2}}; + modes_ = {chip_mode}; + } else { + // V1 Iface combinations for Mode Id = 0. (STA Mode) + const IWifiChip::ChipIfaceCombinationLimit + sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1}; + IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2; + if (feature_flags_.lock()->isAwareSupported()) { + sta_chip_iface_combination_limit_2 = { + {IfaceType::P2P, IfaceType::NAN}, 1}; + } else { + sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 1}; + } + const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = { + {sta_chip_iface_combination_limit_1, + sta_chip_iface_combination_limit_2}}; + const IWifiChip::ChipMode sta_chip_mode = { + kV1StaChipModeId, {sta_chip_iface_combination}}; + // Iface combinations for Mode Id = 1. (AP Mode) + const IWifiChip::ChipIfaceCombinationLimit + ap_chip_iface_combination_limit = {{IfaceType::AP}, 1}; + const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = { + {ap_chip_iface_combination_limit}}; + const IWifiChip::ChipMode ap_chip_mode = {kV1ApChipModeId, + {ap_chip_iface_combination}}; + modes_ = {sta_chip_mode, ap_chip_mode}; + } +} + +std::vector +WifiChip::getCurrentModeIfaceCombinations() { + if (!isValidModeId(current_mode_id_)) { + LOG(ERROR) << "Chip not configured in a mode yet"; + return {}; + } + for (const auto& mode : modes_) { + if (mode.id == current_mode_id_) { + return mode.availableCombinations; + } + } + CHECK(0) << "Expected to find iface combinations for current mode!"; + return {}; +} + +// Returns a map indexed by IfaceType with the number of ifaces currently +// created of the corresponding type. +std::map WifiChip::getCurrentIfaceCombination() { + std::map iface_counts; + iface_counts[IfaceType::AP] = ap_ifaces_.size(); + iface_counts[IfaceType::NAN] = nan_ifaces_.size(); + iface_counts[IfaceType::P2P] = p2p_ifaces_.size(); + iface_counts[IfaceType::STA] = sta_ifaces_.size(); + return iface_counts; +} + +// This expands the provided iface combinations to a more parseable +// form. Returns a vector of available combinations possible with the number +// of ifaces of each type in the combination. +// This method is a port of HalDeviceManager.expandIfaceCombos() from framework. +std::vector> WifiChip::expandIfaceCombinations( + const IWifiChip::ChipIfaceCombination& combination) { + uint32_t num_expanded_combos = 1; + for (const auto& limit : combination.limits) { + for (uint32_t i = 0; i < limit.maxIfaces; i++) { + num_expanded_combos *= limit.types.size(); + } + } + + // Allocate the vector of expanded combos and reset all iface counts to 0 + // in each combo. + std::vector> expanded_combos; + expanded_combos.resize(num_expanded_combos); + for (auto& expanded_combo : expanded_combos) { + for (const auto type : + {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) { + expanded_combo[type] = 0; + } + } + uint32_t span = num_expanded_combos; + for (const auto& limit : combination.limits) { + for (uint32_t i = 0; i < limit.maxIfaces; i++) { + span /= limit.types.size(); + for (uint32_t k = 0; k < num_expanded_combos; ++k) { + const auto iface_type = + limit.types[(k / span) % limit.types.size()]; + expanded_combos[k][iface_type]++; + } + } + } + return expanded_combos; +} + +bool WifiChip::canExpandedIfaceCombinationSupportIfaceOfType( + const std::map& combo, IfaceType requested_type) { + const auto current_combo = getCurrentIfaceCombination(); + + // Check if we have space for 1 more iface of |type| in this combo + for (const auto type : + {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) { + size_t num_ifaces_needed = current_combo.at(type); + if (type == requested_type) { + num_ifaces_needed++; + } + size_t num_ifaces_allowed = combo.at(type); + if (num_ifaces_needed > num_ifaces_allowed) { + return false; + } + } + return true; +} + +// This method does the following: +// a) Enumerate all possible iface combos by expanding the current +// ChipIfaceCombination. +// b) Check if the requested iface type can be added to the current mode. +bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType type) { + if (!isValidModeId(current_mode_id_)) { + LOG(ERROR) << "Chip not configured in a mode yet"; + return false; + } + const auto combinations = getCurrentModeIfaceCombinations(); + for (const auto& combination : combinations) { + const auto expanded_combos = expandIfaceCombinations(combination); + for (const auto& expanded_combo : expanded_combos) { + if (canExpandedIfaceCombinationSupportIfaceOfType(expanded_combo, + type)) { + return true; + } + } + } + return false; +} + +bool WifiChip::isValidModeId(ChipModeId mode_id) { + for (const auto& mode : modes_) { + if (mode.id == mode_id) { + return true; + } + } + return false; +} + +// Return "wlan0", if "wlan0" is not already in use, else return "wlan1". +// This is based on the assumption that we'll have a max of 2 concurrent +// AP/STA ifaces. +std::string WifiChip::allocateApOrStaIfaceName() { + auto ap_iface = findUsingName(ap_ifaces_, getWlan0IfaceName()); + auto sta_iface = findUsingName(sta_ifaces_, getWlan0IfaceName()); + if (!ap_iface.get() && !sta_iface.get()) { + return getWlan0IfaceName(); + } + ap_iface = findUsingName(ap_ifaces_, getWlan1IfaceName()); + sta_iface = findUsingName(sta_ifaces_, getWlan1IfaceName()); + if (!ap_iface.get() && !sta_iface.get()) { + return getWlan1IfaceName(); + } + // This should never happen. We screwed up somewhere if it did. + CHECK(0) << "wlan0 and wlan1 in use already!"; + return {}; +} + } // namespace implementation } // namespace V1_2 } // namespace wifi diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h index ac59d59102..97c434ee6a 100644 --- a/wifi/1.2/default/wifi_chip.h +++ b/wifi/1.2/default/wifi_chip.h @@ -24,6 +24,7 @@ #include "hidl_callback_util.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" @@ -45,10 +46,12 @@ using namespace android::hardware::wifi::V1_0; */ class WifiChip : public V1_1::IWifiChip { public: - WifiChip(ChipId chip_id, - const std::weak_ptr legacy_hal, - const std::weak_ptr - mode_controller); + WifiChip( + ChipId chip_id, + const std::weak_ptr legacy_hal, + const std::weak_ptr + mode_controller, + const std::weak_ptr feature_flags); // HIDL does not provide a built-in mechanism to let the server invalidate // a HIDL interface object after creation. If any client process holds onto // a reference to the object in their context, any method calls on that @@ -190,16 +193,31 @@ class WifiChip : public V1_1::IWifiChip { std::unique_lock* lock, ChipModeId mode_id); WifiStatus registerDebugRingBufferCallback(); + void populateModes(); + std::vector + getCurrentModeIfaceCombinations(); + std::map getCurrentIfaceCombination(); + std::vector> expandIfaceCombinations( + const IWifiChip::ChipIfaceCombination& combination); + bool canExpandedIfaceCombinationSupportIfaceOfType( + const std::map& combo, IfaceType type); + bool canCurrentModeSupportIfaceOfType(IfaceType type); + bool isValidModeId(ChipModeId mode_id); + std::string allocateApOrStaIfaceName(); + ChipId chip_id_; std::weak_ptr legacy_hal_; std::weak_ptr mode_controller_; - sp ap_iface_; - sp nan_iface_; - sp p2p_iface_; - sp sta_iface_; + std::weak_ptr feature_flags_; + std::vector> ap_ifaces_; + std::vector> nan_ifaces_; + std::vector> p2p_ifaces_; + std::vector> sta_ifaces_; std::vector> rtt_controllers_; bool is_valid_; + // Members pertaining to chip configuration. uint32_t current_mode_id_; + std::vector 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. diff --git a/wifi/1.2/default/wifi_feature_flags.cpp b/wifi/1.2/default/wifi_feature_flags.cpp new file mode 100644 index 0000000000..554d4d5f6d --- /dev/null +++ b/wifi/1.2/default/wifi_feature_flags.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wifi_feature_flags.h" + +namespace { +#ifdef WIFI_HIDL_FEATURE_AWARE +static const bool wifiHidlFeatureAware = true; +#else +static const bool wifiHidlFeatureAware = false; +#endif // WIFI_HIDL_FEATURE_AWARE +#ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE +static const bool wifiHidlFeatureDualInterface = true; +#else +static const bool wifiHidlFeatureDualInterface = false; +#endif // WIFI_HIDL_FEATURE_DUAL_INTERFACE +} // namespace + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_2 { +namespace implementation { +namespace feature_flags { + +WifiFeatureFlags::WifiFeatureFlags() {} +bool WifiFeatureFlags::isAwareSupported() { return wifiHidlFeatureAware; } +bool WifiFeatureFlags::isDualInterfaceSupported() { + return wifiHidlFeatureDualInterface; +} + +} // namespace feature_flags +} // namespace implementation +} // namespace V1_2 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.2/default/wifi_feature_flags.h b/wifi/1.2/default/wifi_feature_flags.h index da4ca37e9b..dc0c1ff320 100644 --- a/wifi/1.2/default/wifi_feature_flags.h +++ b/wifi/1.2/default/wifi_feature_flags.h @@ -22,16 +22,18 @@ namespace hardware { namespace wifi { namespace V1_2 { namespace implementation { +namespace feature_flags { class WifiFeatureFlags { public: -#ifdef WIFI_HIDL_FEATURE_AWARE - static const bool wifiHidlFeatureAware = true; -#else - static const bool wifiHidlFeatureAware = false; -#endif // WIFI_HIDL_FEATURE_AWARE + WifiFeatureFlags(); + virtual ~WifiFeatureFlags() = default; + + virtual bool isAwareSupported(); + virtual bool isDualInterfaceSupported(); }; +} // namespace feature_flags } // namespace implementation } // namespace V1_2 } // namespace wifi diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp index 24b80d5046..9abe514a35 100644 --- a/wifi/1.2/default/wifi_legacy_hal.cpp +++ b/wifi/1.2/default/wifi_legacy_hal.cpp @@ -455,7 +455,7 @@ std::pair WifiLegacyHal::getSupportedFeatureSet( const std::string& iface_name) { feature_set set; static_assert(sizeof(set) == sizeof(uint32_t), - "Some features can not be represented in output"); + "Some feature_flags can not be represented in output"); wifi_error status = global_func_table_.wifi_get_supported_feature_set( getIfaceHandle(iface_name), &set); return {status, static_cast(set)}; @@ -759,11 +759,11 @@ wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) { std::pair WifiLegacyHal::getLoggerSupportedFeatureSet( const std::string& iface_name) { - uint32_t supported_features; + uint32_t supported_feature_flags; wifi_error status = global_func_table_.wifi_get_logger_supported_feature_set( - getIfaceHandle(iface_name), &supported_features); - return {status, supported_features}; + getIfaceHandle(iface_name), &supported_feature_flags); + return {status, supported_feature_flags}; } wifi_error WifiLegacyHal::startPktFateMonitoring( diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h index 05f700e59a..da88f6b420 100644 --- a/wifi/1.2/default/wifi_legacy_hal.h +++ b/wifi/1.2/default/wifi_legacy_hal.h @@ -142,15 +142,16 @@ using on_error_alert_callback = class WifiLegacyHal { public: WifiLegacyHal(); + virtual ~WifiLegacyHal() = default; // Initialize the legacy HAL function table. - wifi_error initialize(); + virtual wifi_error initialize(); // Start the legacy HAL and the event looper thread. - wifi_error start(); + virtual wifi_error start(); // Deinitialize the legacy HAL and wait for the event loop thread to exit // using a predefined timeout. - wifi_error stop(std::unique_lock* lock, - const std::function& on_complete_callback); + virtual wifi_error stop(std::unique_lock* lock, + const std::function& on_complete_callback); // Wrappers for all the functions in the legacy HAL function table. std::pair getDriverVersion( const std::string& iface_name); @@ -190,7 +191,7 @@ class WifiLegacyHal { wifi_error stopGscan(const std::string& iface_name, wifi_request_id id); std::pair> getValidFrequenciesForBand( const std::string& iface_name, wifi_band band); - wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on); + 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); @@ -276,12 +277,12 @@ class WifiLegacyHal { wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id, const wifi_lcr_information& info); // NAN functions. - wifi_error nanRegisterCallbackHandlers( + 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); - wifi_error nanDisableRequest(const std::string& iface_name, - transaction_id id); + 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); @@ -312,9 +313,9 @@ class WifiLegacyHal { wifi_error nanDataInterfaceCreate(const std::string& iface_name, transaction_id id, const std::string& data_iface_name); - wifi_error nanDataInterfaceDelete(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); diff --git a/wifi/1.2/default/wifi_mode_controller.cpp b/wifi/1.2/default/wifi_mode_controller.cpp index 8a89e810ba..c286d2439c 100644 --- a/wifi/1.2/default/wifi_mode_controller.cpp +++ b/wifi/1.2/default/wifi_mode_controller.cpp @@ -59,11 +59,15 @@ bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) { convertIfaceTypeToFirmwareMode(type)); } -bool WifiModeController::changeFirmwareMode(IfaceType 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"; diff --git a/wifi/1.2/default/wifi_mode_controller.h b/wifi/1.2/default/wifi_mode_controller.h index 839bf9eeaf..395aa5d9e8 100644 --- a/wifi/1.2/default/wifi_mode_controller.h +++ b/wifi/1.2/default/wifi_mode_controller.h @@ -37,15 +37,17 @@ using namespace android::hardware::wifi::V1_0; class WifiModeController { public: WifiModeController(); + virtual ~WifiModeController() = default; // Checks if a firmware mode change is necessary to support the specified // iface type operations. - bool isFirmwareModeChangeNeeded(IfaceType type); + virtual bool isFirmwareModeChangeNeeded(IfaceType type); + virtual bool initialize(); // Change the firmware mode to support the specified iface type operations. - bool changeFirmwareMode(IfaceType type); + virtual bool changeFirmwareMode(IfaceType type); // Unload the driver. This should be invoked whenever |IWifi.stop()| is // invoked. - bool deinitialize(); + virtual bool deinitialize(); private: std::unique_ptr driver_tool_; diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.2/default/wifi_nan_iface.cpp index e7bbfaaae3..12e4d7b007 100644 --- a/wifi/1.2/default/wifi_nan_iface.cpp +++ b/wifi/1.2/default/wifi_nan_iface.cpp @@ -494,6 +494,8 @@ void WifiNanIface::invalidate() { bool WifiNanIface::isValid() { return is_valid_; } +std::string WifiNanIface::getName() { return ifname_; } + std::set> WifiNanIface::getEventCallbacks() { return event_cb_handler_.getCallbacks(); } diff --git a/wifi/1.2/default/wifi_nan_iface.h b/wifi/1.2/default/wifi_nan_iface.h index 2ca2e45a7d..6fa7b0c1e9 100644 --- a/wifi/1.2/default/wifi_nan_iface.h +++ b/wifi/1.2/default/wifi_nan_iface.h @@ -41,6 +41,7 @@ class WifiNanIface : public V1_0::IWifiNanIface { // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override; diff --git a/wifi/1.2/default/wifi_p2p_iface.cpp b/wifi/1.2/default/wifi_p2p_iface.cpp index f1fbf2c9bc..92bbaee388 100644 --- a/wifi/1.2/default/wifi_p2p_iface.cpp +++ b/wifi/1.2/default/wifi_p2p_iface.cpp @@ -39,6 +39,8 @@ void WifiP2pIface::invalidate() { bool WifiP2pIface::isValid() { return is_valid_; } +std::string WifiP2pIface::getName() { return ifname_; } + Return WifiP2pIface::getName(getName_cb hidl_status_cb) { return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID, &WifiP2pIface::getNameInternal, hidl_status_cb); diff --git a/wifi/1.2/default/wifi_p2p_iface.h b/wifi/1.2/default/wifi_p2p_iface.h index 839d3c35b6..76120b1574 100644 --- a/wifi/1.2/default/wifi_p2p_iface.h +++ b/wifi/1.2/default/wifi_p2p_iface.h @@ -39,6 +39,7 @@ class WifiP2pIface : public V1_0::IWifiP2pIface { // Refer to |WifiChip::invalidate()|. void invalidate(); bool isValid(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override; diff --git a/wifi/1.2/default/wifi_sta_iface.cpp b/wifi/1.2/default/wifi_sta_iface.cpp index c8605eedaa..6faf009379 100644 --- a/wifi/1.2/default/wifi_sta_iface.cpp +++ b/wifi/1.2/default/wifi_sta_iface.cpp @@ -49,6 +49,8 @@ void WifiStaIface::invalidate() { bool WifiStaIface::isValid() { return is_valid_; } +std::string WifiStaIface::getName() { return ifname_; } + std::set> WifiStaIface::getEventCallbacks() { return event_cb_handler_.getCallbacks(); } diff --git a/wifi/1.2/default/wifi_sta_iface.h b/wifi/1.2/default/wifi_sta_iface.h index 6731864dec..423365cfbd 100644 --- a/wifi/1.2/default/wifi_sta_iface.h +++ b/wifi/1.2/default/wifi_sta_iface.h @@ -42,6 +42,7 @@ class WifiStaIface : public V1_0::IWifiStaIface { void invalidate(); bool isValid(); std::set> getEventCallbacks(); + std::string getName(); // HIDL methods exposed. Return getName(getName_cb hidl_status_cb) override;