blob: f4c40764e596b3ebc6c6d67e8bff7f40793caad4 [file] [log] [blame]
/*
* 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