| /* |
| * 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 "wificond/scanning/offload/offload_scan_manager.h" |
| |
| #include <vector> |
| |
| #include <android-base/logging.h> |
| |
| #include "wificond/scanning/offload/hidl_call_util.h" |
| #include "wificond/scanning/offload/offload_scan_utils.h" |
| #include "wificond/scanning/offload/offload_service_utils.h" |
| #include "wificond/scanning/offload/scan_stats.h" |
| #include "wificond/scanning/scan_result.h" |
| |
| using android::hardware::wifi::offload::V1_0::IOffload; |
| using android::hardware::wifi::offload::V1_0::ScanResult; |
| using android::hardware::wifi::offload::V1_0::ScanFilter; |
| using android::hardware::wifi::offload::V1_0::ScanParam; |
| using android::hardware::wifi::offload::V1_0::ScanStats; |
| using android::hardware::wifi::offload::V1_0::OffloadStatus; |
| using android::hardware::wifi::offload::V1_0::OffloadStatusCode; |
| |
| using ::com::android::server::wifi::wificond::NativeScanResult; |
| using ::com::android::server::wifi::wificond::NativeScanStats; |
| using std::vector; |
| using std::weak_ptr; |
| using std::shared_ptr; |
| |
| using namespace std::placeholders; |
| |
| namespace { |
| const uint32_t kSubscriptionDelayMs = 5000; |
| } |
| |
| namespace android { |
| namespace wificond { |
| |
| OffloadCallbackHandlersImpl::OffloadCallbackHandlersImpl( |
| OffloadScanManager* offload_scan_manager) |
| : offload_scan_manager_(offload_scan_manager) {} |
| |
| OffloadCallbackHandlersImpl::~OffloadCallbackHandlersImpl() {} |
| |
| void OffloadCallbackHandlersImpl::OnScanResultHandler( |
| const vector<ScanResult>& scanResult) { |
| if (offload_scan_manager_ != nullptr) { |
| offload_scan_manager_->ReportScanResults(scanResult); |
| } |
| } |
| |
| void OffloadCallbackHandlersImpl::OnErrorHandler(const OffloadStatus& status) { |
| if (offload_scan_manager_ != nullptr) { |
| offload_scan_manager_->ReportError(status); |
| } |
| } |
| |
| OffloadScanManager::OffloadScanManager( |
| weak_ptr<OffloadServiceUtils> utils, |
| shared_ptr<OffloadScanCallbackInterface> callback) |
| : wifi_offload_hal_(nullptr), |
| wifi_offload_callback_(nullptr), |
| death_recipient_(nullptr), |
| offload_status_(OffloadScanManager::kError), |
| service_available_(false), |
| offload_service_utils_(utils), |
| offload_callback_handlers_(new OffloadCallbackHandlersImpl(this)), |
| event_callback_(callback) { |
| if (InitService()) { |
| offload_status_ = OffloadScanManager::kNoError; |
| } |
| } |
| |
| bool OffloadScanManager::InitService() { |
| wifi_offload_hal_ = offload_service_utils_.lock()->GetOffloadService(); |
| if (wifi_offload_hal_ == nullptr) { |
| LOG(ERROR) << "No Offload Service available"; |
| return false; |
| } |
| |
| death_recipient_ = offload_service_utils_.lock()->GetOffloadDeathRecipient( |
| std::bind(&OffloadScanManager::OnObjectDeath, this, _1)); |
| uint64_t cookie = reinterpret_cast<uint64_t>(wifi_offload_hal_.get()); |
| |
| auto link_to_death_status = |
| wifi_offload_hal_->linkToDeath(death_recipient_, cookie); |
| if (!link_to_death_status.isOk()) { |
| LOG(ERROR) << "Unable to register death handler " |
| << link_to_death_status.description(); |
| return false; |
| } |
| |
| wifi_offload_callback_ = offload_service_utils_.lock()->GetOffloadCallback( |
| offload_callback_handlers_.get()); |
| if (wifi_offload_callback_ == nullptr) { |
| LOG(ERROR) << "Invalid Offload callback object"; |
| return false; |
| } |
| |
| auto set_callback_status = |
| wifi_offload_hal_->setEventCallback(wifi_offload_callback_); |
| if (!set_callback_status.isOk()) { |
| LOG(ERROR) << "Unable to set event callback for Offload HAL"; |
| return false; |
| } |
| |
| service_available_ = true; |
| return true; |
| } |
| |
| bool OffloadScanManager::InitServiceIfNeeded() { |
| if (!service_available_) { |
| return InitService(); |
| } |
| return true; |
| } |
| |
| bool OffloadScanManager::stopScan(OffloadScanManager::ReasonCode* reason_code) { |
| if (!InitServiceIfNeeded() || |
| (getOffloadStatus() != OffloadScanManager::kNoError)) { |
| *reason_code = OffloadScanManager::kNotAvailable; |
| return false; |
| } |
| const auto& res = wifi_offload_hal_->unsubscribeScanResults(); |
| if (!res.isOk()) { |
| *reason_code = OffloadScanManager::kTransactionFailed; |
| LOG(WARNING) << "unsubscribeScanResults() failed " << res.description(); |
| return false; |
| } |
| *reason_code = OffloadScanManager::kNone; |
| return true; |
| } |
| |
| bool OffloadScanManager::GetScanStats(NativeScanStats* native_scan_stats) { |
| const auto& result = HIDL_INVOKE(wifi_offload_hal_, getScanStats); |
| const auto& offload_status_and_scan_stats = result.first; |
| bool transport_status = result.second; |
| if (!transport_status) { |
| return false; |
| } |
| OffloadStatus offload_status = offload_status_and_scan_stats.first; |
| ScanStats scan_stats = offload_status_and_scan_stats.second; |
| if (offload_status.code != OffloadStatusCode::OK) { |
| LOG(WARNING) << offload_status.description; |
| return false; |
| } |
| *native_scan_stats = OffloadScanUtils::convertToNativeScanStats(scan_stats); |
| return true; |
| } |
| |
| bool OffloadScanManager::VerifyAndConvertHIDLStatus( |
| std::pair<OffloadStatus, bool> result, |
| OffloadScanManager::ReasonCode* reason_code) { |
| const auto& offload_status = result.first; |
| bool transport_status = result.second; |
| if (!transport_status) { |
| *reason_code = OffloadScanManager::kTransactionFailed; |
| return false; |
| } |
| if (offload_status.code != OffloadStatusCode::OK) { |
| LOG(WARNING) << offload_status.description; |
| *reason_code = OffloadScanManager::kOperationFailed; |
| return false; |
| } |
| return true; |
| } |
| |
| bool OffloadScanManager::startScan( |
| uint32_t interval_ms, int32_t rssi_threshold, |
| const vector<vector<uint8_t>>& scan_ssids, |
| const vector<vector<uint8_t>>& match_ssids, |
| const vector<uint8_t>& match_security, const vector<uint32_t>& freqs, |
| OffloadScanManager::ReasonCode* reason_code) { |
| if (!InitServiceIfNeeded() || |
| getOffloadStatus() != OffloadScanManager::kNoError) { |
| *reason_code = OffloadScanManager::kNotAvailable; |
| LOG(WARNING) << "Offload HAL scans are not available"; |
| return false; |
| } |
| ScanParam param = |
| OffloadScanUtils::createScanParam(scan_ssids, freqs, interval_ms); |
| ScanFilter filter = OffloadScanUtils::createScanFilter( |
| match_ssids, match_security, rssi_threshold); |
| |
| if (!ConfigureScans(param, filter, reason_code)) { |
| return false; |
| } |
| |
| if (!SubscribeScanResults(reason_code)) { |
| return false; |
| } |
| |
| *reason_code = OffloadScanManager::kNone; |
| return true; |
| } |
| |
| bool OffloadScanManager::ConfigureScans( |
| ScanParam param, ScanFilter filter, |
| OffloadScanManager::ReasonCode* reason_code) { |
| const auto& result = |
| HIDL_INVOKE(wifi_offload_hal_, configureScans, param, filter); |
| if (!VerifyAndConvertHIDLStatus(result, reason_code)) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool OffloadScanManager::SubscribeScanResults( |
| OffloadScanManager::ReasonCode* reason_code) { |
| const auto& result = HIDL_INVOKE(wifi_offload_hal_, subscribeScanResults, |
| kSubscriptionDelayMs); |
| if (!VerifyAndConvertHIDLStatus(result, reason_code)) { |
| return false; |
| } |
| return true; |
| } |
| |
| OffloadScanManager::StatusCode OffloadScanManager::getOffloadStatus() const { |
| if (!service_available_) { |
| return OffloadScanManager::kNoService; |
| } |
| return offload_status_; |
| } |
| |
| bool OffloadScanManager::getScanResults( |
| std::vector<NativeScanResult>* out_scan_results) { |
| for (const auto& scan_result : cached_scan_results_) { |
| out_scan_results->push_back(scan_result); |
| } |
| return true; |
| } |
| |
| bool OffloadScanManager::getScanStats(NativeScanStats* native_scan_stats) { |
| if (!InitServiceIfNeeded()) { |
| LOG(ERROR) << "Offload HAL service unavailable"; |
| return false; |
| } |
| if (getOffloadStatus() != OffloadScanManager::kNoError) { |
| LOG(WARNING) << "Unable to get scan stats due to Wifi Offload HAL error"; |
| return false; |
| } |
| return GetScanStats(native_scan_stats); |
| } |
| |
| OffloadScanManager::~OffloadScanManager() { |
| if (wifi_offload_hal_ != nullptr) { |
| wifi_offload_hal_->unlinkToDeath(death_recipient_); |
| } |
| } |
| |
| void OffloadScanManager::ReportScanResults( |
| const vector<ScanResult>& scanResult) { |
| cached_scan_results_.clear(); |
| if (!OffloadScanUtils::convertToNativeScanResults(scanResult, |
| &cached_scan_results_)) { |
| LOG(WARNING) << "Unable to convert scan results to native format"; |
| return; |
| } |
| if (event_callback_ != nullptr) { |
| event_callback_->OnOffloadScanResult(); |
| } else { |
| LOG(WARNING) |
| << "No callback to report Offload HAL's scan results to wificond"; |
| } |
| } |
| |
| void OffloadScanManager::ReportError(const OffloadStatus& status) { |
| OffloadStatusCode status_code = status.code; |
| OffloadScanManager::StatusCode status_result = OffloadScanManager::kNoError; |
| switch (status_code) { |
| case OffloadStatusCode::OK: |
| status_result = OffloadScanManager::kNoError; |
| break; |
| case OffloadStatusCode::TIMEOUT: |
| status_result = OffloadScanManager::kTimeOut; |
| break; |
| case OffloadStatusCode::NO_CONNECTION: |
| status_result = OffloadScanManager::kNotConnected; |
| break; |
| case OffloadStatusCode::ERROR: |
| status_result = OffloadScanManager::kError; |
| break; |
| default: |
| LOG(WARNING) << "Invalid Offload Error reported"; |
| return; |
| } |
| if (status_result != OffloadScanManager::kNoError) { |
| LOG(WARNING) << "Offload Error reported " << status.description; |
| if (event_callback_ != nullptr) { |
| event_callback_->OnOffloadError( |
| OffloadScanCallbackInterface::REMOTE_FAILURE); |
| } else { |
| LOG(WARNING) << "No callback to report Offload HAL Errors to wificond"; |
| } |
| } |
| offload_status_ = status_result; |
| } |
| |
| void OffloadScanManager::OnObjectDeath(uint64_t cookie) { |
| if (wifi_offload_hal_ == reinterpret_cast<IOffload*>(cookie)) { |
| LOG(ERROR) << "Death Notification for Wifi Offload HAL"; |
| wifi_offload_hal_.clear(); |
| if (event_callback_ != nullptr) { |
| event_callback_->OnOffloadError( |
| OffloadScanCallbackInterface::BINDER_DEATH); |
| } else { |
| LOG(WARNING) |
| << "No callback to report Offload HAL Binder death to wificond"; |
| } |
| service_available_ = false; |
| death_recipient_.clear(); |
| } |
| } |
| |
| } // namespace wificond |
| } // namespace android |