diff --git a/wifi/1.0/IWifi.hal b/wifi/1.0/IWifi.hal index 1feeb2a9f4..d1311f5462 100644 --- a/wifi/1.0/IWifi.hal +++ b/wifi/1.0/IWifi.hal @@ -28,8 +28,12 @@ interface IWifi { /** * Requests notifications of significant events for the HAL. Multiple calls to * this must register multiple callbacks each of which must receive all - * events. IWifiEventCallback registration must be independent of the state - * of the rest of the HAL and must persist though stops/starts. + * events. |IWifiEventCallback| object registration must be independent of the + * state of the rest of the HAL and must persist though stops/starts. These + * objects must be deleted when the corresponding client process is dead. + * + * @param callback An instance of the |IWifiEventCallback| HIDL interface + * object. */ @entry @callflow(next={"*"}) @@ -37,6 +41,8 @@ interface IWifi { /** * Get the current state of the HAL. + * + * @return started true if started, false otherwise. */ isStarted() generates (bool started); diff --git a/wifi/1.0/IWifiChip.hal b/wifi/1.0/IWifiChip.hal index f5fe7a9e82..7a41ddf1b7 100644 --- a/wifi/1.0/IWifiChip.hal +++ b/wifi/1.0/IWifiChip.hal @@ -24,7 +24,7 @@ import IWifiChipEventCallback; * to perform operations like NAN, RTT, etc. */ interface IWifiChip { - enum InterfaceType : uint32_t { + enum IfaceType : uint32_t { STA, AP, P2P, /** * NAN control interface. Datapath support may be queried and created @@ -35,11 +35,11 @@ interface IWifiChip { /** * Set of interface types with the maximum number of interfaces that can have - * one of the specified type for a given ChipInterfaceCombination. See - * ChipInterfaceCombination for examples. + * one of the specified type for a given ChipIfaceCombination. See + * ChipIfaceCombination for examples. */ - struct ChipInterfaceCombinationLimit { - vec types; // Each InterfaceType may occur at most once + struct ChipIfaceCombinationLimit { + vec types; // Each IfaceType may occur at most once uint32_t maxIfaces; }; @@ -66,8 +66,8 @@ interface IWifiChip { * [], [STA], [STA+NAN], [STA+STA], [NAN] * Not included [STA+STA+NAN] */ - struct ChipInterfaceCombination { - vec limits; + struct ChipIfaceCombination { + vec limits; }; /** @@ -80,7 +80,7 @@ interface IWifiChip { * * When in a mode, it must be possible to perform any combination of creating * and removing interfaces as long as at least one of the - * ChipInterfaceCombinations is satisfied. This means that if a chip has two + * ChipIfaceCombinations is satisfied. This means that if a chip has two * available combinations, [{STA} <= 1] and [{AP} <= 1] then it is expected * that exactly one STA interface or one AP interface can be created, but it * is not expected that both a STA and AP interface could be created. If it @@ -118,48 +118,62 @@ interface IWifiChip { * A list of the possible interface combinations that the chip can have * while in this mode. */ - vec availableCombinations; + vec availableCombinations; }; /** * Requests notifications of significant events on this chip. Multiple calls * to this will register multiple callbacks each of which will receive all * events. + * + * @param callback An instance of the |IWifiChipEventCallback| HIDL interface + * object. */ oneway registerEventCallback(IWifiChipEventCallback callback); /** * Get the set of operation modes that the chip supports. + * + * @return modes List of modes supported by the device. */ getAvailableModes() generates (vec modes); /** - * Reconfigure the Chip. Will trigger onChipReconfigured. + * Reconfigure the Chip. + * Must trigger |IWifiChipEventCallback.onChipReconfigured| on sucess, + * or |IWifiChipEventCallback.onChipReconfigureFailure| on failure. * * @param modeId The mode that the chip should switch to, corresponding to the - * id property of the target ChipMode. + * id property of the target ChipMode. */ oneway configureChip(ChipModeId modeId); /** * Get the current mode that the chip is in. + * + * @return modeId The mode that the chip is currently configured to, + * corresponding to the id property of the target ChipMode. */ getMode() generates (ChipModeId modeId); /** - * Request information about the chip. Will trigger onChipDebugInfoAvailable. + * Request information about the chip. + * Must trigger |IWifiChipEventCallback.onChipDebugInfoAvailable| on sucess, + * or |IWifiChipEventCallback.onChipDebugInfoFailure| on failure. */ oneway requestChipDebugInfo(); /** - * Request vendor debug info from the driver. Will trigger - * onDriverDebugDumpAvailable. + * Request vendor debug info from the driver. + * Must trigger |IWifiChipEventCallback.onDriverDebugDumpAvailable| on success, + * or |IWifiChipEventCallback.onDriverDebugDumpFailure| on failure. */ oneway requestDriverDebugDump(); /** - * Request vendor debug info from the firmware. Will trigger - * onFirmwareDebugDumpAvailable. + * Request vendor debug info from the firmware. + * Must trigger |IWifiChipEventCallback.onFirmwareDebugDumpAvailable| on + * success, or |IWifiChipEventCallback.onFirmwareDebugDumpFailure| on failure. */ oneway requestFirmwareDebugDump(); }; diff --git a/wifi/1.0/IWifiChipEventCallback.hal b/wifi/1.0/IWifiChipEventCallback.hal index 79f6d2a764..2161c5d4a7 100644 --- a/wifi/1.0/IWifiChipEventCallback.hal +++ b/wifi/1.0/IWifiChipEventCallback.hal @@ -24,7 +24,7 @@ interface IWifiChipEventCallback { * considered invalid. * * @param modeId The mode that the chip switched to, corresponding to the id - * property of the target ChipMode. + * property of the target ChipMode. */ oneway onChipReconfigured(ChipModeId modeId); @@ -34,7 +34,8 @@ interface IWifiChipEventCallback { * assumed to be invalid. * * @param modeId The mode that the chip failed switched to, corresponding to - * the id property of the target ChipMode. + * the id property of the target ChipMode. + * @param reason Failure reason code. */ oneway onChipReconfigureFailure(ChipModeId modeId, FailureReason reason); @@ -51,18 +52,45 @@ interface IWifiChipEventCallback { /** * Callback with debug information about this chip + * + * @param info Instance of |ChipDebugInfo|. */ oneway onChipDebugInfoAvailable(ChipDebugInfo info); /** - * Callback with a vendor specific debug blob from the driver. - * This blob will be dumped as part of the bug report. + * Callback to be invoked on failure to fetch debug info about this chip. + * + * @param reason Failure reason code. */ - oneway onDriverDebugDumpAvailable(vec blob); + oneway onChipDebugInfoFailure(FailureReason reason); /** * Callback with a vendor specific debug blob from the driver. * This blob will be dumped as part of the bug report. + * + * @param blob Vector of bytes retrieved from the driver. + */ + oneway onDriverDebugDumpAvailable(vec blob); + + /** + * Callback to be invoked on failure to fetch debug blob from driver. + * + * @param reason Failure reason code. + */ + oneway onDriverDebugDumpFailure(FailureReason reason); + + /** + * Callback with a vendor specific debug blob from the driver. + * This blob will be dumped as part of the bug report. + * + * @param blob Vector of bytes retrieved from the driver. */ oneway onFirmwareDebugDumpAvailable(vec blob); + + /** + * Callback to be invoked on failure to fetch debug blob from driver. + * + * @param reason Failure reason code. + */ + oneway onFirmwareDebugDumpFailure(FailureReason reason); }; diff --git a/wifi/1.0/IWifiEventCallback.hal b/wifi/1.0/IWifiEventCallback.hal index 84025cec9f..33accff8ea 100644 --- a/wifi/1.0/IWifiEventCallback.hal +++ b/wifi/1.0/IWifiEventCallback.hal @@ -28,6 +28,8 @@ interface IWifiEventCallback { * failed. After this callback the HAL will be considered stopped. Another * call to start will attempt to reinitialize the HAL; however, there is a * chance it may fail again. + * + * @param reason Failure reason code. */ oneway onStartFailure(FailureReason reason); @@ -43,6 +45,8 @@ interface IWifiEventCallback { * Calling start again must restart Wi-Fi as if stop then start was called * (full state reset). When this event is received all IWifiChip objects * retrieved after the last call to start will be considered invalid. + * + * @param reason Failure reason code. */ oneway onFailure(FailureReason reason); }; diff --git a/wifi/1.0/default/Android.mk b/wifi/1.0/default/Android.mk new file mode 100644 index 0000000000..07865a5df7 --- /dev/null +++ b/wifi/1.0/default/Android.mk @@ -0,0 +1,57 @@ +# 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. +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.wifi@1.0-impl +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_CPPFLAGS := -std=c++11 -Wall -Wno-unused-parameter -Werror -Wextra +LOCAL_SRC_FILES := \ + failure_reason_util.cpp \ + wifi_chip.cpp \ + wifi.cpp \ + wifi_legacy_hal.cpp +LOCAL_SHARED_LIBRARIES := \ + android.hardware.wifi@1.0 \ + libbase \ + libcutils \ + libhidl \ + libhwbinder \ + liblog \ + libnl \ + libutils \ + libwifi-system +LOCAL_WHOLE_STATIC_LIBRARIES := $(LIB_WIFI_HAL) +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.wifi@1.0-service +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_CPPFLAGS := -std=c++11 -Wall -Wno-unused-parameter -Werror -Wextra +LOCAL_SRC_FILES := \ + service.cpp +LOCAL_SHARED_LIBRARIES := \ + android.hardware.wifi@1.0 \ + android.hardware.wifi@1.0-impl \ + libbase \ + libcutils \ + libhidl \ + libhwbinder \ + liblog \ + libnl \ + libutils \ + libwifi-system +LOCAL_WHOLE_STATIC_LIBRARIES := $(LIB_WIFI_HAL) +LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc +include $(BUILD_EXECUTABLE) diff --git a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc new file mode 100644 index 0000000000..9d09347d84 --- /dev/null +++ b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc @@ -0,0 +1,4 @@ +service wifi_hal_legacy /system/bin/hw/android.hardware.wifi@1.0-service + class hal + user wifi + group wifi diff --git a/wifi/1.0/default/failure_reason_util.cpp b/wifi/1.0/default/failure_reason_util.cpp new file mode 100644 index 0000000000..f703ebe2c2 --- /dev/null +++ b/wifi/1.0/default/failure_reason_util.cpp @@ -0,0 +1,96 @@ +/* + * 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 "failure_reason_util.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +std::string LegacyErrorToString(wifi_error error) { + switch (error) { + case WIFI_SUCCESS: + return "SUCCESS"; + case WIFI_ERROR_UNINITIALIZED: + return "UNINITIALIZED"; + case WIFI_ERROR_NOT_AVAILABLE: + return "NOT_AVAILABLE"; + case WIFI_ERROR_NOT_SUPPORTED: + return "NOT_SUPPORTED"; + case WIFI_ERROR_INVALID_ARGS: + return "INVALID_ARGS"; + case WIFI_ERROR_INVALID_REQUEST_ID: + return "INVALID_REQUEST_ID"; + case WIFI_ERROR_TIMED_OUT: + return "TIMED_OUT"; + case WIFI_ERROR_TOO_MANY_REQUESTS: + return "TOO_MANY_REQUESTS"; + case WIFI_ERROR_OUT_OF_MEMORY: + return "OUT_OF_MEMORY"; + case WIFI_ERROR_UNKNOWN: + default: + return "UNKNOWN"; + } +} + +FailureReason CreateFailureReason(CommandFailureReason reason, + const std::string& description) { + FailureReason result; + result.reason = reason; + result.description = description.data(); + return result; +} + +FailureReason CreateFailureReasonLegacyError(wifi_error error, + const std::string& desc) { + switch (error) { + case WIFI_ERROR_UNINITIALIZED: + case WIFI_ERROR_NOT_AVAILABLE: + return CreateFailureReason(CommandFailureReason::NOT_AVAILABLE, desc); + + case WIFI_ERROR_NOT_SUPPORTED: + return CreateFailureReason(CommandFailureReason::NOT_SUPPORTED, desc); + + case WIFI_ERROR_INVALID_ARGS: + case WIFI_ERROR_INVALID_REQUEST_ID: + return CreateFailureReason(CommandFailureReason::INVALID_ARGS, desc); + + case WIFI_ERROR_TIMED_OUT: + return CreateFailureReason(CommandFailureReason::UNKNOWN, + desc + ", timed out"); + + case WIFI_ERROR_TOO_MANY_REQUESTS: + return CreateFailureReason(CommandFailureReason::UNKNOWN, + desc + ", too many requests"); + + case WIFI_ERROR_OUT_OF_MEMORY: + return CreateFailureReason(CommandFailureReason::UNKNOWN, + desc + ", out of memory"); + + case WIFI_ERROR_NONE: + case WIFI_ERROR_UNKNOWN: + default: + return CreateFailureReason(CommandFailureReason::UNKNOWN, "unknown"); + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.0/default/failure_reason_util.h b/wifi/1.0/default/failure_reason_util.h new file mode 100644 index 0000000000..7d51bbf2fe --- /dev/null +++ b/wifi/1.0/default/failure_reason_util.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FAILURE_REASON_UTIL_H_ +#define FAILURE_REASON_UTIL_H_ + +#include +#include + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +std::string LegacyErrorToString(wifi_error error); + +FailureReason CreateFailureReason(CommandFailureReason reason, + const std::string& description); +FailureReason CreateFailureReasonLegacyError(wifi_error error, + const std::string& description); + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // FAILURE_REASON_UTIL_H_ diff --git a/wifi/1.0/default/service.cpp b/wifi/1.0/default/service.cpp new file mode 100644 index 0000000000..10ce1dbadd --- /dev/null +++ b/wifi/1.0/default/service.cpp @@ -0,0 +1,69 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "wifi.h" + +using android::hardware::hidl_version; +using android::hardware::IPCThreadState; +using android::hardware::ProcessState; +using android::Looper; + +namespace { +int OnBinderReadReady(int /*fd*/, int /*events*/, void* /*data*/) { + IPCThreadState::self()->handlePolledCommands(); + return 1; // continue receiving events +} +} + +int main(int /*argc*/, char** argv) { + android::base::InitLogging(argv, + android::base::LogdLogger(android::base::SYSTEM)); + LOG(INFO) << "wifi_hal_legacy is starting up..."; + + // Setup binder + int binder_fd = -1; + ProcessState::self()->setThreadPoolMaxThreadCount(0); + CHECK_EQ(IPCThreadState::self()->setupPolling(&binder_fd), android::NO_ERROR) + << "Failed to initialize binder polling"; + CHECK_GE(binder_fd, 0) << "Invalid binder FD: " << binder_fd; + + // Setup looper + android::sp looper = Looper::prepare(0 /* no options */); + CHECK(looper->addFd( + binder_fd, 0, Looper::EVENT_INPUT, OnBinderReadReady, nullptr)) + << "Failed to watch binder FD"; + + // Setup hwbinder service + android::sp service = + new android::hardware::wifi::V1_0::implementation::Wifi(); + CHECK_EQ(service->registerAsService("wifi"), android::NO_ERROR) + << "Failed to register wifi HAL"; + + // Loop + while (looper->pollAll(-1) != Looper::POLL_ERROR) { + // Keep polling until failure. + } + + LOG(INFO) << "wifi_hal_legacy is terminating..."; + return 0; +} diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.0/default/wifi.cpp new file mode 100644 index 0000000000..d5b69b815d --- /dev/null +++ b/wifi/1.0/default/wifi.cpp @@ -0,0 +1,120 @@ +/* + * 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.h" + +#include + +#include "failure_reason_util.h" +#include "wifi_chip.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +Wifi::Wifi() + : legacy_hal_(new WifiLegacyHal()), run_state_(RunState::STOPPED) {} + +Return Wifi::registerEventCallback( + const sp& callback) { + // TODO(b/31632518): remove the callback when the client is destroyed + callbacks_.insert(callback); + return Void(); +} + +Return Wifi::isStarted() { + return run_state_ != RunState::STOPPED; +} + +Return Wifi::start() { + if (run_state_ == RunState::STARTED) { + for (const auto& callback : callbacks_) { + callback->onStart(); + } + return Void(); + } else if (run_state_ == RunState::STOPPING) { + for (const auto& callback : callbacks_) { + callback->onStartFailure(CreateFailureReason( + CommandFailureReason::NOT_AVAILABLE, "HAL is stopping")); + } + return Void(); + } + + LOG(INFO) << "Starting HAL"; + wifi_error status = legacy_hal_->start(); + if (status != WIFI_SUCCESS) { + LOG(ERROR) << "Failed to start Wifi HAL"; + for (auto& callback : callbacks_) { + callback->onStartFailure( + CreateFailureReasonLegacyError(status, "Failed to start HAL")); + } + return Void(); + } + + // Create the chip instance once the HAL is started. + chip_ = new WifiChip(legacy_hal_); + run_state_ = RunState::STARTED; + for (const auto& callback : callbacks_) { + callback->onStart(); + } + return Void(); +} + +Return Wifi::stop() { + if (run_state_ == RunState::STOPPED) { + for (const auto& callback : callbacks_) { + callback->onStop(); + } + return Void(); + } else if (run_state_ == RunState::STOPPING) { + return Void(); + } + + LOG(INFO) << "Stopping HAL"; + run_state_ = RunState::STOPPING; + const auto on_complete_callback_ = [&]() { + if (chip_.get()) { + chip_->invalidate(); + } + chip_.clear(); + run_state_ = RunState::STOPPED; + for (const auto& callback : callbacks_) { + callback->onStop(); + } + }; + wifi_error status = legacy_hal_->stop(on_complete_callback_); + if (status != WIFI_SUCCESS) { + LOG(ERROR) << "Failed to stop Wifi HAL"; + for (const auto& callback : callbacks_) { + callback->onFailure( + CreateFailureReasonLegacyError(status, "Failed to stop HAL")); + } + } + return Void(); +} + +Return Wifi::getChip(getChip_cb cb) { + cb(chip_); + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.0/default/wifi.h b/wifi/1.0/default/wifi.h new file mode 100644 index 0000000000..e6cf1acbe8 --- /dev/null +++ b/wifi/1.0/default/wifi.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WIFI_H_ +#define WIFI_H_ + +#include +#include + +#include +#include +#include + +#include "wifi_chip.h" +#include "wifi_legacy_hal.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +/** + * Root HIDL interface object used to control the Wifi HAL. + */ +class Wifi : public IWifi { + public: + Wifi(); + + // HIDL methods exposed. + Return registerEventCallback( + const sp& callback) override; + Return isStarted() override; + Return start() override; + Return stop() override; + Return getChip(getChip_cb cb) override; + + private: + enum class RunState { STOPPED, STARTED, STOPPING }; + + // Instance is created in this root level |IWifi| HIDL interface object + // and shared with all the child HIDL interface objects. + std::shared_ptr legacy_hal_; + RunState run_state_; + std::set> callbacks_; + sp chip_; + + DISALLOW_COPY_AND_ASSIGN(Wifi); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // WIFI_H_ diff --git a/wifi/1.0/default/wifi_chip.cpp b/wifi/1.0/default/wifi_chip.cpp new file mode 100644 index 0000000000..df321e2103 --- /dev/null +++ b/wifi/1.0/default/wifi_chip.cpp @@ -0,0 +1,147 @@ +/* + * 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_chip.h" + +#include + +#include "failure_reason_util.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +WifiChip::WifiChip(std::weak_ptr legacy_hal) + : legacy_hal_(legacy_hal) {} + +void WifiChip::invalidate() { + legacy_hal_.reset(); + callbacks_.clear(); +} + +Return WifiChip::registerEventCallback( + const sp& callback) { + if (!legacy_hal_.lock()) + return Void(); + // TODO(b/31632518): remove the callback when the client is destroyed + callbacks_.insert(callback); + return Void(); +} + +Return WifiChip::getAvailableModes(getAvailableModes_cb cb) { + if (!legacy_hal_.lock()) { + cb(hidl_vec()); + return Void(); + } else { + // TODO add implementation + return Void(); + } +} + +Return WifiChip::configureChip(uint32_t /*mode_id*/) { + if (!legacy_hal_.lock()) + return Void(); + // TODO add implementation + return Void(); +} + +Return WifiChip::getMode() { + if (!legacy_hal_.lock()) + return 0; + // TODO add implementation + return 0; +} + +Return WifiChip::requestChipDebugInfo() { + if (!legacy_hal_.lock()) + return Void(); + + IWifiChipEventCallback::ChipDebugInfo result; + + std::pair ret = + legacy_hal_.lock()->getWlanDriverVersion(); + if (ret.first != WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get driver version: " + << LegacyErrorToString(ret.first); + return Void(); + } + result.driverDescription = ret.second.c_str(); + + ret = legacy_hal_.lock()->getWlanFirmwareVersion(); + if (ret.first != WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get firmware version: " + << LegacyErrorToString(ret.first); + return Void(); + } + result.firmwareDescription = ret.second.c_str(); + + for (const auto& callback : callbacks_) { + callback->onChipDebugInfoAvailable(result); + } + return Void(); +} + +Return WifiChip::requestDriverDebugDump() { + if (!legacy_hal_.lock()) + return Void(); + + std::pair> ret = + legacy_hal_.lock()->requestWlanDriverMemoryDump(); + if (ret.first != WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get driver debug dump: " + << LegacyErrorToString(ret.first); + return Void(); + } + + auto& driver_dump = ret.second; + hidl_vec hidl_data; + hidl_data.setToExternal(reinterpret_cast(driver_dump.data()), + driver_dump.size()); + for (const auto& callback : callbacks_) { + callback->onDriverDebugDumpAvailable(hidl_data); + } + return Void(); +} + +Return WifiChip::requestFirmwareDebugDump() { + if (!legacy_hal_.lock()) + return Void(); + + std::pair> ret = + legacy_hal_.lock()->requestWlanFirmwareMemoryDump(); + if (ret.first != WIFI_SUCCESS) { + LOG(ERROR) << "Failed to get firmware debug dump: " + << LegacyErrorToString(ret.first); + return Void(); + } + + auto& firmware_dump = ret.second; + hidl_vec hidl_data; + hidl_data.setToExternal(reinterpret_cast(firmware_dump.data()), + firmware_dump.size()); + for (const auto& callback : callbacks_) { + callback->onFirmwareDebugDumpAvailable(hidl_data); + } + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.0/default/wifi_chip.h b/wifi/1.0/default/wifi_chip.h new file mode 100644 index 0000000000..95fabe465e --- /dev/null +++ b/wifi/1.0/default/wifi_chip.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WIFI_CHIP_H_ +#define WIFI_CHIP_H_ + +#include + +#include +#include + +#include "wifi_legacy_hal.h" + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +/** + * HIDL 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 IWifiChip { + public: + WifiChip(std::weak_ptr legacy_hal); + // Invalidate this instance once the HAL is stopped. + void invalidate(); + + // HIDL methods exposed. + Return registerEventCallback( + const sp& callback) override; + Return getAvailableModes(getAvailableModes_cb cb) override; + Return configureChip(uint32_t mode_id) override; + Return getMode() override; + Return requestChipDebugInfo() override; + Return requestDriverDebugDump() override; + Return requestFirmwareDebugDump() override; + + private: + std::weak_ptr legacy_hal_; + std::set> callbacks_; + + DISALLOW_COPY_AND_ASSIGN(WifiChip); +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // WIFI_CHIP_H_ diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp new file mode 100644 index 0000000000..a6df996fc1 --- /dev/null +++ b/wifi/1.0/default/wifi_legacy_hal.cpp @@ -0,0 +1,211 @@ +/* + * 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 + +#include "failure_reason_util.h" +#include "wifi_legacy_hal.h" + +#include +#include +#include +#include + +namespace { +std::string getWlanInterfaceName() { + char buffer[PROPERTY_VALUE_MAX]; + property_get("wifi.interface", buffer, "wlan0"); + return buffer; +} + +// Legacy HAL functions accept "C" style function pointers, so use global +// functions to pass to the legacy HAL function and store the corresponding +// std::function methods to be invoked. +// Callback to be invoked once |stop| is complete. +std::function on_stop_complete_internal_callback; +void onStopComplete(wifi_handle handle) { + if (on_stop_complete_internal_callback) { + on_stop_complete_internal_callback(handle); + } +} + +// Callback to be invoked for driver dump. +std::function on_driver_memory_dump_internal_callback; +void onDriverMemoryDump(char* buffer, int buffer_size) { + if (on_driver_memory_dump_internal_callback) { + on_driver_memory_dump_internal_callback(buffer, buffer_size); + } +} + +// Callback to be invoked for firmware dump. +std::function on_firmware_memory_dump_internal_callback; +void onFirmwareMemoryDump(char* buffer, int buffer_size) { + if (on_firmware_memory_dump_internal_callback) { + on_firmware_memory_dump_internal_callback(buffer, buffer_size); + } +} +} + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +const uint32_t WifiLegacyHal::kMaxVersionStringLength = 256; + +WifiLegacyHal::WifiLegacyHal() + : global_handle_(nullptr), + wlan_interface_handle_(nullptr), + awaiting_event_loop_termination_(false) {} + +wifi_error WifiLegacyHal::start() { + // Ensure that we're starting in a good state. + CHECK(!global_handle_ && !wlan_interface_handle_ && + !awaiting_event_loop_termination_); + + android::wifi_system::HalTool hal_tool; + android::wifi_system::InterfaceTool if_tool; + if (!hal_tool.InitFunctionTable(&global_func_table_)) { + LOG(ERROR) << "Failed to initialize legacy hal function table"; + return WIFI_ERROR_UNKNOWN; + } + if (!if_tool.SetWifiUpState(true)) { + LOG(ERROR) << "Failed to set WiFi interface up"; + return WIFI_ERROR_UNKNOWN; + } + + LOG(INFO) << "Starting legacy HAL"; + wifi_error status = global_func_table_.wifi_initialize(&global_handle_); + if (status != WIFI_SUCCESS || !global_handle_) { + LOG(ERROR) << "Failed to retrieve global handle"; + return status; + } + event_loop_thread_ = std::thread(&WifiLegacyHal::runEventLoop, this); + status = retrieveWlanInterfaceHandle(); + if (status != WIFI_SUCCESS || !wlan_interface_handle_) { + LOG(ERROR) << "Failed to retrieve wlan interface handle"; + return status; + } + LOG(VERBOSE) << "Legacy HAL start complete"; + return WIFI_SUCCESS; +} + +wifi_error WifiLegacyHal::stop( + const std::function& on_stop_complete_user_callback) { + LOG(INFO) << "Stopping legacy HAL"; + on_stop_complete_internal_callback = [&](wifi_handle handle) { + CHECK_EQ(global_handle_, handle) << "Handle mismatch"; + on_stop_complete_user_callback(); + global_handle_ = nullptr; + wlan_interface_handle_ = nullptr; + on_stop_complete_internal_callback = nullptr; + }; + awaiting_event_loop_termination_ = true; + global_func_table_.wifi_cleanup(global_handle_, onStopComplete); + LOG(VERBOSE) << "Legacy HAL stop initiated"; + return WIFI_SUCCESS; +} + +std::pair WifiLegacyHal::getWlanDriverVersion() { + std::array buffer; + buffer.fill(0); + wifi_error status = global_func_table_.wifi_get_driver_version( + wlan_interface_handle_, buffer.data(), buffer.size()); + return std::make_pair(status, buffer.data()); +} + +std::pair WifiLegacyHal::getWlanFirmwareVersion() { + std::array buffer; + buffer.fill(0); + wifi_error status = global_func_table_.wifi_get_firmware_version( + wlan_interface_handle_, buffer.data(), buffer.size()); + return std::make_pair(status, buffer.data()); +} + +std::pair> +WifiLegacyHal::requestWlanDriverMemoryDump() { + std::vector driver_dump; + on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer, + int buffer_size) { + driver_dump.insert(driver_dump.end(), buffer, buffer + buffer_size); + }; + wifi_error status = global_func_table_.wifi_get_driver_memory_dump( + wlan_interface_handle_, {onDriverMemoryDump}); + on_driver_memory_dump_internal_callback = nullptr; + return std::make_pair(status, std::move(driver_dump)); +} + +std::pair> +WifiLegacyHal::requestWlanFirmwareMemoryDump() { + std::vector firmware_dump; + on_firmware_memory_dump_internal_callback = [&firmware_dump]( + char* buffer, int buffer_size) { + firmware_dump.insert(firmware_dump.end(), buffer, buffer + buffer_size); + }; + wifi_error status = global_func_table_.wifi_get_firmware_memory_dump( + wlan_interface_handle_, {onFirmwareMemoryDump}); + on_firmware_memory_dump_internal_callback = nullptr; + return std::make_pair(status, std::move(firmware_dump)); +} + +wifi_error WifiLegacyHal::retrieveWlanInterfaceHandle() { + const std::string& ifname_to_find = getWlanInterfaceName(); + + wifi_interface_handle* iface_handles = nullptr; + int num_iface_handles = 0; + wifi_error status = global_func_table_.wifi_get_ifaces( + global_handle_, &num_iface_handles, &iface_handles); + if (status != WIFI_SUCCESS) { + LOG(ERROR) << "Failed to enumerate interface handles: " + << LegacyErrorToString(status); + return status; + } + for (int i = 0; i < num_iface_handles; ++i) { + std::array current_ifname; + current_ifname.fill(0); + status = global_func_table_.wifi_get_iface_name( + iface_handles[i], current_ifname.data(), current_ifname.size()); + if (status != WIFI_SUCCESS) { + LOG(WARNING) << "Failed to get interface handle name: " + << LegacyErrorToString(status); + continue; + } + if (ifname_to_find == current_ifname.data()) { + wlan_interface_handle_ = iface_handles[i]; + return WIFI_SUCCESS; + } + } + return WIFI_ERROR_UNKNOWN; +} + +void WifiLegacyHal::runEventLoop() { + LOG(VERBOSE) << "Starting legacy HAL event loop"; + global_func_table_.wifi_event_loop(global_handle_); + if (!awaiting_event_loop_termination_) { + LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping"; + } + LOG(VERBOSE) << "Legacy HAL event loop terminated"; + awaiting_event_loop_termination_ = false; + android::wifi_system::InterfaceTool if_tool; + if_tool.SetWifiUpState(false); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h new file mode 100644 index 0000000000..f691b9ba5c --- /dev/null +++ b/wifi/1.0/default/wifi_legacy_hal.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WIFI_LEGACY_WIFI_HAL_H_ +#define WIFI_LEGACY_WIFI_HAL_H_ + +#include +#include + +#include + +namespace android { +namespace hardware { +namespace wifi { +namespace V1_0 { +namespace implementation { + +/** + * Class that encapsulates all legacy HAL interactions. + * This class manages the lifetime of the event loop thread used by legacy HAL. + */ +class WifiLegacyHal { + public: + WifiLegacyHal(); + // Initialize the legacy HAL and start the event looper thread. + wifi_error start(); + // Deinitialize the legacy HAL and stop the event looper thread. + wifi_error stop(const std::function& on_complete_callback); + // Wrappers for all the functions in the legacy HAL function table. + std::pair getWlanDriverVersion(); + std::pair getWlanFirmwareVersion(); + std::pair> requestWlanDriverMemoryDump(); + std::pair> requestWlanFirmwareMemoryDump(); + + private: + static const uint32_t kMaxVersionStringLength; + + // Retrieve the interface handle to be used for the "wlan" interface. + wifi_error retrieveWlanInterfaceHandle(); + // Run the legacy HAL event loop thread. + void runEventLoop(); + + // Event loop thread used by legacy HAL. + std::thread event_loop_thread_; + // 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_; + // Opaque handle to be used for all wlan0 interface specific operations. + wifi_interface_handle wlan_interface_handle_; + // Flag to indicate if we have initiated the cleanup of legacy HAL. + bool awaiting_event_loop_termination_; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // WIFI_LEGACY_WIFI_HAL_H_