#include "offload_server.h" #include <android-base/logging.h> #include <chre/apps/wifi_offload/flatbuffers_serialization.h> #include <chre/apps/wifi_offload/host_message_types.h> #include "offload_status_util.h" #include "offload_utils.h" using namespace android::hardware::wifi::offload::V1_0::implementation::chre_constants; using android::hardware::wifi::offload::V1_0::OffloadStatus; namespace { constexpr auto kScanStatsTimeout = std::chrono::milliseconds(500); } namespace android { namespace hardware { namespace wifi { namespace offload { namespace V1_0 { namespace implementation { class OffloadServer; OffloadServer::OffloadServer(ChreInterfaceFactory* factory) : mChreInterfaceCallbacks(new ChreInterfaceCallbacksImpl(this)), mChreInterface(factory->getChreInterface(mChreInterfaceCallbacks.get())) { LOG(VERBOSE) << "Wifi Offload HAL impl"; } OffloadStatus OffloadServer::configureScans(const ScanParam& param, const ScanFilter& filter) { LOG(INFO) << "configureScans"; if (!mChreInterface->isConnected()) { return createOffloadStatus(OffloadStatusCode::NO_CONNECTION, "Not connected to hardware implementation"); } wifi_offload::ScanConfig scanConfig; if (!offload_utils::ToChreScanConfig(param, filter, &scanConfig)) { return createOffloadStatus(OffloadStatusCode::ERROR, "Unable to convert scan configuration"); } uint8_t buffer[kMaxMessageLen]; size_t result_size = wifi_offload::fbs::Serialize(scanConfig, buffer, kMaxMessageLen); if (result_size <= 0) { return createOffloadStatus(OffloadStatusCode::ERROR, "Scan config serialization failed"); } std::vector<uint8_t> message(buffer, buffer + result_size); if (!mChreInterface->sendCommandToApp(wifi_offload::HostMessageType::HOST_CMD_CONFIG_SCANS, message)) { return createOffloadStatus(OffloadStatusCode::ERROR, "Unable to send config message"); } return createOffloadStatus(OffloadStatusCode::OK); } std::pair<OffloadStatus, ScanStats> OffloadServer::getScanStats() { LOG(INFO) << "getScanStats"; mScanStatsStatus = createOffloadStatus(OffloadStatusCode::OK); if (!mChreInterface->isConnected()) { return {createOffloadStatus(OffloadStatusCode::NO_CONNECTION, "Unable to send scan stats"), {}}; } if (!mChreInterface->sendCommandToApp(wifi_offload::HostMessageType::HOST_CMD_GET_SCAN_STATS, {})) { return {createOffloadStatus(OffloadStatusCode::ERROR, "Unable to send scan stats command"), {}}; } LOG(VERBOSE) << "Sent getScanStats command"; { std::unique_lock<std::mutex> lock(mScanStatsLock); auto timeout_status = mScanStatsCond.wait_for(lock, kScanStatsTimeout); if (timeout_status == std::cv_status::timeout) { std::lock_guard<std::mutex> lock(mOffloadLock); LOG(WARNING) << "Timeout waiting for scan stats"; return {createOffloadStatus(OffloadStatusCode::TIMEOUT, "Scan stats not received"), {}}; } } return std::make_pair(mScanStatsStatus, mScanStats); } OffloadStatus OffloadServer::subscribeScanResults(uint32_t delayMs) { LOG(INFO) << "subscribeScanResults with delay:" << delayMs; if (!mChreInterface->isConnected()) { return createOffloadStatus(OffloadStatusCode::NO_CONNECTION, "Not connected to hardware"); } uint32_t* buffer = &delayMs; std::vector<uint8_t> message(reinterpret_cast<uint8_t*>(buffer), reinterpret_cast<uint8_t*>(buffer) + kSubscriptionDelayMsBufLen); if (!mChreInterface->sendCommandToApp( wifi_offload::HostMessageType::HOST_CMD_SUBSCRIBE_SCAN_RESULTS, message)) { return createOffloadStatus(OffloadStatusCode::ERROR, "Unable to request scans"); } return createOffloadStatus(OffloadStatusCode::OK); } void OffloadServer::resetNanoApp() { LOG(INFO) << "resetting Nano app"; if (!mChreInterface->isConnected()) { LOG(WARNING) << "Unable to reset nano app, not connected"; return; } if (!mChreInterface->sendCommandToApp(wifi_offload::HostMessageType::HOST_CMD_RESET, {})) { LOG(ERROR) << "Unable to send Reset command to Nano app"; } } bool OffloadServer::unsubscribeScanResults() { LOG(INFO) << "unsubscribeScanResults"; if (!mChreInterface->isConnected()) { LOG(WARNING) << "Failed to send unsubscribe scan results message"; return false; } if (!mChreInterface->sendCommandToApp( wifi_offload::HostMessageType::HOST_CMD_UNSUBSCRIBE_SCAN_RESULTS, {})) { LOG(WARNING) << "Failed to send unsubscribe scan results message"; return false; } return true; } bool OffloadServer::setEventCallback(const sp<IOffloadCallback>& cb) { LOG(INFO) << "Set Event callback"; if (cb == nullptr) { return false; } std::lock_guard<std::mutex> lock(mOffloadLock); mEventCallback = cb; return true; } void OffloadServer::clearEventCallback() { std::lock_guard<std::mutex> lock(mOffloadLock); if (mEventCallback != nullptr) { mEventCallback.clear(); } LOG(INFO) << "Event callback cleared"; } void OffloadServer::invokeErrorCallbackAndResetIfNeeded(const OffloadStatus& status) { if (status.code != OffloadStatusCode::OK) { resetNanoApp(); } std::lock_guard<std::mutex> lock(mOffloadLock); if (mEventCallback != nullptr) { mEventCallback->onError(status); } } ChreInterfaceCallbacksImpl::ChreInterfaceCallbacksImpl(OffloadServer* server) : mServer(server) { } ChreInterfaceCallbacksImpl::~ChreInterfaceCallbacksImpl() { } void ChreInterfaceCallbacksImpl::handleConnectionEvents( ChreInterfaceCallbacks::ConnectionEvent event) { switch (event) { case ChreInterfaceCallbacks::ConnectionEvent::DISCONNECTED: case ChreInterfaceCallbacks::ConnectionEvent::CONNECTION_ABORT: { LOG(ERROR) << "Connection to socket lost"; mServer->invokeErrorCallbackAndResetIfNeeded( createOffloadStatus(OffloadStatusCode::NO_CONNECTION, "Connection to socket lost")); } break; case ChreInterfaceCallbacks::ConnectionEvent::CONNECTED: { LOG(INFO) << "Connected to socket"; mServer->invokeErrorCallbackAndResetIfNeeded( createOffloadStatus(OffloadStatusCode::OK)); } break; default: LOG(WARNING) << "Invalid connection event received " << (int)event; break; } } void OffloadServer::handleScanResult(const std::vector<uint8_t>& message) { std::vector<wifi_offload::ScanResult> scanResults; std::vector<ScanResult> hidlScanResults; std::string errorMessage; if (!wifi_offload::fbs::Deserialize((uint8_t*)message.data(), message.size(), &scanResults)) { invokeErrorCallbackAndResetIfNeeded( createOffloadStatus(OffloadStatusCode::ERROR, "Cannot deserialize scan results")); return; } if (!offload_utils::ToHidlScanResults(scanResults, &hidlScanResults)) { invokeErrorCallbackAndResetIfNeeded(createOffloadStatus( OffloadStatusCode::ERROR, "Cannot convert scan results to HIDL format")); return; } { std::lock_guard<std::mutex> lock(mOffloadLock); if (mEventCallback != nullptr) { mEventCallback->onScanResult(hidlScanResults); } } } void OffloadServer::handleScanStats(const std::vector<uint8_t>& message) { std::lock_guard<std::mutex> lock(mScanStatsLock); wifi_offload::ScanStats stats; OffloadStatus status; // Deserialize scan stats status = createOffloadStatus(OffloadStatusCode::OK); LOG(VERBOSE) << "Received scan stats"; if (!wifi_offload::fbs::Deserialize((uint8_t*)message.data(), message.size(), &stats)) { status = createOffloadStatus(OffloadStatusCode::ERROR, "Cannot deserailize scan stats"); } else if (!offload_utils::ToHidlScanStats(stats, &mScanStats)) { status = createOffloadStatus(OffloadStatusCode::ERROR, "Cannot convert Scan stats to HIDL format"); } mScanStatsStatus = status; mScanStatsCond.notify_all(); } void ChreInterfaceCallbacksImpl::handleMessage(uint32_t messageType, const std::vector<uint8_t>& message) { LOG(VERBOSE) << "Message from Nano app " << messageType; switch (messageType) { case wifi_offload::HostMessageType::HOST_MSG_SCAN_RESULTS: { LOG(INFO) << "Received scan results"; mServer->handleScanResult(message); } break; case wifi_offload::HostMessageType::HOST_MSG_SCAN_STATS: LOG(VERBOSE) << "Received scan stats from Nano app"; mServer->handleScanStats(message); break; case wifi_offload::HostMessageType::HOST_MSG_ERROR: LOG(VERBOSE) << "Received error message from Nano app"; { std::string errorMessage; if (offload_utils::ToHidlErrorMessage(message[0], &errorMessage)) { mServer->invokeErrorCallbackAndResetIfNeeded( createOffloadStatus(OffloadStatusCode::ERROR, errorMessage)); } } break; default: LOG(WARNING) << "Unknown message received" << messageType; break; } } // Methods from ::android::hidl::base::V1_0::IBase follow. } // namespace implementation } // namespace V1_0 } // namespace offload } // namespace wifi } // namespace hardware } // namespace android