| #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 |