1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "wificond/scanning/offload/offload_scan_manager.h"
17
18#include <vector>
19
20#include <android-base/logging.h>
21
22#include "wificond/scanning/offload/hidl_call_util.h"
23#include "wificond/scanning/offload/offload_scan_utils.h"
24#include "wificond/scanning/offload/offload_service_utils.h"
25#include "wificond/scanning/offload/scan_stats.h"
26#include "wificond/scanning/scan_result.h"
27
28using ::android::hardware::hidl_vec;
29using android::hardware::wifi::offload::V1_0::IOffload;
30using android::hardware::wifi::offload::V1_0::ScanResult;
31using android::hardware::wifi::offload::V1_0::ScanFilter;
32using android::hardware::wifi::offload::V1_0::ScanParam;
33using android::hardware::wifi::offload::V1_0::ScanStats;
34using android::hardware::wifi::offload::V1_0::OffloadStatus;
35using android::hardware::wifi::offload::V1_0::OffloadStatusCode;
36
37using android::wificond::OffloadCallback;
38using ::com::android::server::wifi::wificond::NativeScanResult;
39using ::com::android::server::wifi::wificond::NativeScanStats;
40using std::vector;
41using std::weak_ptr;
42using std::shared_ptr;
43
44using namespace std::placeholders;
45
46namespace {
47const uint32_t kSubscriptionDelayMs = 5000;
48}
49
50namespace android {
51namespace wificond {
52
53OffloadCallbackHandlersImpl::OffloadCallbackHandlersImpl(
54    OffloadScanManager* offload_scan_manager)
55    : offload_scan_manager_(offload_scan_manager) {}
56
57OffloadCallbackHandlersImpl::~OffloadCallbackHandlersImpl() {}
58
59void OffloadCallbackHandlersImpl::OnScanResultHandler(
60    const vector<ScanResult>& scanResult) {
61  if (offload_scan_manager_ != nullptr) {
62    offload_scan_manager_->ReportScanResults(scanResult);
63  }
64}
65
66void OffloadCallbackHandlersImpl::OnErrorHandler(const OffloadStatus& status) {
67  if (offload_scan_manager_ != nullptr) {
68    offload_scan_manager_->ReportError(status);
69  }
70}
71
72OffloadScanManager::OffloadScanManager(
73    weak_ptr<OffloadServiceUtils> utils,
74    shared_ptr<OffloadScanCallbackInterface> callback)
75    : wifi_offload_hal_(nullptr),
76      wifi_offload_callback_(nullptr),
77      death_recipient_(nullptr),
78      offload_status_(OffloadScanManager::kError),
79      service_available_(false),
80      offload_service_utils_(utils),
81      offload_callback_handlers_(new OffloadCallbackHandlersImpl(this)),
82      event_callback_(callback) {
83  if (InitService()) {
84    offload_status_ = OffloadScanManager::kNoError;
85  }
86}
87
88bool OffloadScanManager::InitService() {
89  wifi_offload_hal_ = offload_service_utils_.lock()->GetOffloadService();
90  if (wifi_offload_hal_ == nullptr) {
91    LOG(ERROR) << "No Offload Service available";
92    return false;
93  }
94
95  death_recipient_ = offload_service_utils_.lock()->GetOffloadDeathRecipient(
96      std::bind(&OffloadScanManager::OnObjectDeath, this, _1));
97  uint64_t cookie = reinterpret_cast<uint64_t>(wifi_offload_hal_.get());
98
99  auto link_to_death_status =
100      wifi_offload_hal_->linkToDeath(death_recipient_, cookie);
101  if (!link_to_death_status.isOk()) {
102    LOG(ERROR) << "Unable to register death handler "
103               << link_to_death_status.description();
104    return false;
105  }
106
107  wifi_offload_callback_ = offload_service_utils_.lock()->GetOffloadCallback(
108      offload_callback_handlers_.get());
109  if (wifi_offload_callback_ == nullptr) {
110    LOG(ERROR) << "Invalid Offload callback object";
111    return false;
112  }
113
114  auto set_callback_status =
115      wifi_offload_hal_->setEventCallback(wifi_offload_callback_);
116  if (!set_callback_status.isOk()) {
117    LOG(ERROR) << "Unable to set event callback for Offload HAL";
118    return false;
119  }
120
121  service_available_ = true;
122  return true;
123}
124
125bool OffloadScanManager::InitServiceIfNeeded() {
126  if (!service_available_) {
127    return InitService();
128  }
129  return true;
130}
131
132bool OffloadScanManager::stopScan(OffloadScanManager::ReasonCode* reason_code) {
133  if (!InitServiceIfNeeded() ||
134      (getOffloadStatus() != OffloadScanManager::kNoError)) {
135    *reason_code = OffloadScanManager::kNotAvailable;
136    return false;
137  }
138  const auto& res = wifi_offload_hal_->unsubscribeScanResults();
139  if (!res.isOk()) {
140    *reason_code = OffloadScanManager::kTransactionFailed;
141    LOG(WARNING) << "unsubscribeScanResults() failed " << res.description();
142    return false;
143  }
144  *reason_code = OffloadScanManager::kNone;
145  return true;
146}
147
148bool OffloadScanManager::GetScanStats(NativeScanStats* native_scan_stats) {
149  const auto& result = HIDL_INVOKE(wifi_offload_hal_, getScanStats);
150  const auto& offload_status_and_scan_stats = result.first;
151  bool transport_status = result.second;
152  if (!transport_status) {
153    return false;
154  }
155  OffloadStatus offload_status = offload_status_and_scan_stats.first;
156  ScanStats scan_stats = offload_status_and_scan_stats.second;
157  if (offload_status.code != OffloadStatusCode::OK) {
158    LOG(WARNING) << offload_status.description;
159    return false;
160  }
161  *native_scan_stats = OffloadScanUtils::convertToNativeScanStats(scan_stats);
162  return true;
163}
164
165bool OffloadScanManager::VerifyAndConvertHIDLStatus(
166    std::pair<OffloadStatus, bool> result,
167    OffloadScanManager::ReasonCode* reason_code) {
168  const auto& offload_status = result.first;
169  bool transport_status = result.second;
170  if (!transport_status) {
171    *reason_code = OffloadScanManager::kTransactionFailed;
172    return false;
173  }
174  if (offload_status.code != OffloadStatusCode::OK) {
175    LOG(WARNING) << offload_status.description;
176    *reason_code = OffloadScanManager::kOperationFailed;
177    return false;
178  }
179  return true;
180}
181
182bool OffloadScanManager::startScan(
183    uint32_t interval_ms, int32_t rssi_threshold,
184    const vector<vector<uint8_t>>& scan_ssids,
185    const vector<vector<uint8_t>>& match_ssids,
186    const vector<uint8_t>& match_security, const vector<uint32_t>& freqs,
187    OffloadScanManager::ReasonCode* reason_code) {
188  if (!InitServiceIfNeeded() ||
189      getOffloadStatus() != OffloadScanManager::kNoError) {
190    *reason_code = OffloadScanManager::kNotAvailable;
191    LOG(WARNING) << "Offload HAL scans are not available";
192    return false;
193  }
194  ScanParam param =
195      OffloadScanUtils::createScanParam(scan_ssids, freqs, interval_ms);
196  ScanFilter filter = OffloadScanUtils::createScanFilter(
197      match_ssids, match_security, rssi_threshold);
198
199  if (!ConfigureScans(param, filter, reason_code)) {
200    return false;
201  }
202
203  if (!SubscribeScanResults(reason_code)) {
204    return false;
205  }
206
207  *reason_code = OffloadScanManager::kNone;
208  return true;
209}
210
211bool OffloadScanManager::ConfigureScans(
212    ScanParam param, ScanFilter filter,
213    OffloadScanManager::ReasonCode* reason_code) {
214  const auto& result =
215      HIDL_INVOKE(wifi_offload_hal_, configureScans, param, filter);
216  if (!VerifyAndConvertHIDLStatus(result, reason_code)) {
217    return false;
218  }
219  return true;
220}
221
222bool OffloadScanManager::SubscribeScanResults(
223    OffloadScanManager::ReasonCode* reason_code) {
224  const auto& result = HIDL_INVOKE(wifi_offload_hal_, subscribeScanResults,
225                                   kSubscriptionDelayMs);
226  if (!VerifyAndConvertHIDLStatus(result, reason_code)) {
227    return false;
228  }
229  return true;
230}
231
232OffloadScanManager::StatusCode OffloadScanManager::getOffloadStatus() const {
233  if (!service_available_) {
234    return OffloadScanManager::kNoService;
235  }
236  return offload_status_;
237}
238
239bool OffloadScanManager::getScanResults(
240    std::vector<NativeScanResult>* out_scan_results) {
241  for (const auto& scan_result : cached_scan_results_) {
242    out_scan_results->push_back(scan_result);
243  }
244  return true;
245}
246
247bool OffloadScanManager::getScanStats(NativeScanStats* native_scan_stats) {
248  if (!InitServiceIfNeeded()) {
249    LOG(ERROR) << "Offload HAL service unavailable";
250    return false;
251  }
252  if (getOffloadStatus() != OffloadScanManager::kNoError) {
253    LOG(WARNING) << "Unable to get scan stats due to Wifi Offload HAL error";
254    return false;
255  }
256  return GetScanStats(native_scan_stats);
257}
258
259OffloadScanManager::~OffloadScanManager() {
260  if (wifi_offload_hal_ != nullptr) {
261    wifi_offload_hal_->unlinkToDeath(death_recipient_);
262  }
263}
264
265void OffloadScanManager::ReportScanResults(
266    const vector<ScanResult>& scanResult) {
267  cached_scan_results_.clear();
268  if (!OffloadScanUtils::convertToNativeScanResults(scanResult,
269                                                    &cached_scan_results_)) {
270    LOG(WARNING) << "Unable to convert scan results to native format";
271    return;
272  }
273  if (event_callback_ != nullptr) {
274    event_callback_->OnOffloadScanResult();
275  } else {
276    LOG(WARNING)
277        << "No callback to report Offload HAL's scan results to wificond";
278  }
279}
280
281void OffloadScanManager::ReportError(const OffloadStatus& status) {
282  OffloadStatusCode status_code = status.code;
283  OffloadScanManager::StatusCode status_result = OffloadScanManager::kNoError;
284  switch (status_code) {
285    case OffloadStatusCode::OK:
286      status_result = OffloadScanManager::kNoError;
287      break;
288    case OffloadStatusCode::TIMEOUT:
289      status_result = OffloadScanManager::kTimeOut;
290      break;
291    case OffloadStatusCode::NO_CONNECTION:
292      status_result = OffloadScanManager::kNotConnected;
293      break;
294    case OffloadStatusCode::ERROR:
295      status_result = OffloadScanManager::kError;
296      break;
297    default:
298      LOG(WARNING) << "Invalid Offload Error reported";
299      return;
300  }
301  if (status_result != OffloadScanManager::kNoError) {
302    LOG(WARNING) << "Offload Error reported " << status.description;
303    if (event_callback_ != nullptr) {
304      event_callback_->OnOffloadError(
305          OffloadScanCallbackInterface::REMOTE_FAILURE);
306    } else {
307      LOG(WARNING) << "No callback to report Offload HAL Errors to wificond";
308    }
309  }
310  offload_status_ = status_result;
311}
312
313void OffloadScanManager::OnObjectDeath(uint64_t cookie) {
314  if (wifi_offload_hal_ == reinterpret_cast<IOffload*>(cookie)) {
315    LOG(ERROR) << "Death Notification for Wifi Offload HAL";
316    wifi_offload_hal_.clear();
317    if (event_callback_ != nullptr) {
318      event_callback_->OnOffloadError(
319          OffloadScanCallbackInterface::BINDER_DEATH);
320    } else {
321      LOG(WARNING)
322          << "No callback to report Offload HAL Binder death to wificond";
323    }
324    service_available_ = false;
325    death_recipient_.clear();
326  }
327}
328
329}  // namespace wificond
330}  // namespace android
331