blob: c23efedd0893c319422ee2a2f7a58787d38731d3 [file] [log] [blame]
/* * Copyright (C) 2020 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 "chre_cross_validator_wifi_manager.h"
#include <stdio.h>
#include <cinttypes>
#include <cstring>
#include "chre/util/nanoapp/assert.h"
#include "chre/util/nanoapp/callbacks.h"
#include "chre/util/nanoapp/log.h"
#include "chre_cross_validation_wifi.nanopb.h"
#include "chre_test_common.nanopb.h"
#define LOG_TAG "ChreCrossValidatorWifi"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
namespace chre {
namespace cross_validator_wifi {
// Fake scan monitor cookie which is not used
constexpr uint32_t kScanMonitoringCookie = 0;
void Manager::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
const void *eventData) {
switch (eventType) {
case CHRE_EVENT_MESSAGE_FROM_HOST:
handleMessageFromHost(
senderInstanceId,
static_cast<const chreMessageFromHostData *>(eventData));
break;
case CHRE_EVENT_WIFI_ASYNC_RESULT:
handleWifiAsyncResult(static_cast<const chreAsyncResult *>(eventData));
break;
case CHRE_EVENT_WIFI_SCAN_RESULT:
handleWifiScanResult(static_cast<const chreWifiScanEvent *>(eventData));
break;
default:
LOGE("Unknown message type %" PRIu16 "received when handling event",
eventType);
}
}
void Manager::handleMessageFromHost(uint32_t senderInstanceId,
const chreMessageFromHostData *hostData) {
if (senderInstanceId != CHRE_INSTANCE_ID) {
LOGE("Incorrect sender instance id: %" PRIu32, senderInstanceId);
} else {
mCrossValidatorState.hostEndpoint = hostData->hostEndpoint;
switch (hostData->messageType) {
case chre_cross_validation_wifi_MessageType_STEP_START: {
pb_istream_t stream = pb_istream_from_buffer(
static_cast<const pb_byte_t *>(
const_cast<const void *>(hostData->message)),
hostData->messageSize);
chre_cross_validation_wifi_StepStartCommand stepStartCommand;
if (!pb_decode(&stream,
chre_cross_validation_wifi_StepStartCommand_fields,
&stepStartCommand)) {
LOGE("Error decoding StepStartCommand");
} else {
handleStepStartMessage(stepStartCommand);
}
break;
}
case chre_cross_validation_wifi_MessageType_SCAN_RESULT:
handleDataMessage(hostData);
break;
default:
LOGE("Unknown message type %" PRIu32 " for host message",
hostData->messageType);
}
}
}
void Manager::handleStepStartMessage(
chre_cross_validation_wifi_StepStartCommand stepStartCommand) {
switch (stepStartCommand.step) {
case chre_cross_validation_wifi_Step_INIT:
LOGE("Received StepStartCommand for INIT step");
CHRE_ASSERT(false);
break;
case chre_cross_validation_wifi_Step_CAPABILITIES: {
chre_cross_validation_wifi_WifiCapabilities wifiCapabilities =
makeWifiCapabilitiesMessage(chreWifiGetCapabilities());
encodeAndSendMessageToHost(
static_cast<void *>(&wifiCapabilities),
chre_cross_validation_wifi_WifiCapabilities_fields,
chre_cross_validation_wifi_MessageType_WIFI_CAPABILITIES);
break;
}
case chre_cross_validation_wifi_Step_SETUP: {
if (!chreWifiConfigureScanMonitorAsync(true /* enable */,
&kScanMonitoringCookie)) {
LOGE("chreWifiConfigureScanMonitorAsync() failed");
chre_test_common_TestResult testResult =
makeTestResultProtoMessage(false, "setupWifiScanMonitoring failed");
encodeAndSendMessageToHost(
static_cast<void *>(&testResult),
chre_test_common_TestResult_fields,
chre_cross_validation_wifi_MessageType_STEP_RESULT);
} else {
LOGD("chreWifiConfigureScanMonitorAsync() succeeded");
}
break;
}
case chre_cross_validation_wifi_Step_VALIDATE:
LOGE("start message received in VALIDATE phase");
break;
}
mStep = stepStartCommand.step;
}
void Manager::handleDataMessage(const chreMessageFromHostData *hostData) {
pb_istream_t stream =
pb_istream_from_buffer(reinterpret_cast<const pb_byte_t *>(
const_cast<const void *>(hostData->message)),
hostData->messageSize);
WifiScanResult scanResult(&stream);
uint8_t scanResultIndex = scanResult.getResultIndex();
mApScanResultsSize = scanResult.getTotalNumResults();
if (scanResultIndex > mApScanResultsSize) {
LOGE("AP scan result index is greater than scan results size");
} else {
mApScanResults[scanResultIndex] = scanResult;
if (scanResult.isLastMessage()) {
mApDataCollectionDone = true;
if (mChreDataCollectionDone) {
compareAndSendResultToHost();
}
}
}
}
void Manager::handleWifiScanResult(const chreWifiScanEvent *event) {
for (uint8_t i = 0; i < event->resultCount; i++) {
mChreScanResults[mChreScanResultsI++] = WifiScanResult(event->results[i]);
}
mNumResultsProcessed += event->resultCount;
if (mNumResultsProcessed >= event->resultTotal) {
mChreScanResultsSize = mChreScanResultsI;
mChreDataCollectionDone = true;
if (mApDataCollectionDone) {
compareAndSendResultToHost();
}
}
}
void Manager::compareAndSendResultToHost() {
constexpr uint16_t kMaxSizeErrMsg = 1000;
char *errMsg = static_cast<char *>(chreHeapAlloc(kMaxSizeErrMsg));
chre_test_common_TestResult testResult;
if (errMsg == nullptr) {
LOG_OOM();
} else {
memset(errMsg, 0, kMaxSizeErrMsg);
// Logging all info about the scan results for debug purposes
if (mApScanResultsSize != mChreScanResultsSize) {
testResult = makeTestResultProtoMessage(
false, "There is a different number of AP and CHRE scan results.");
LOGE("AP and CHRE wifi scan result counts differ, AP = %" PRIu8
", CHRE = %" PRIu8,
mApScanResultsSize, mChreScanResultsSize);
} else {
for (uint8_t i = 0; i < mApScanResultsSize; i++) {
if (!WifiScanResult::areEqual(mApScanResults[i], mChreScanResults[i])) {
testResult = makeTestResultProtoMessage(
false, "One of the AP and CHRE scan results are not equal.");
LOGE("The AP and CHRE scan results are not equal on index %" PRIu8,
i);
}
}
}
encodeAndSendMessageToHost(
static_cast<const void *>(&testResult),
chre_test_common_TestResult_fields,
chre_cross_validation_wifi_MessageType_STEP_RESULT);
chreHeapFree(errMsg);
}
}
bool Manager::encodeErrorMessage(pb_ostream_t *stream,
const pb_field_t * /*field*/,
void *const *arg) {
const char *str = static_cast<const char *>(const_cast<const void *>(*arg));
size_t len = strlen(str);
return pb_encode_tag_for_field(
stream, &chre_test_common_TestResult_fields
[chre_test_common_TestResult_errorMessage_tag - 1]) &&
pb_encode_string(stream, reinterpret_cast<const pb_byte_t *>(str),
len);
}
chre_test_common_TestResult Manager::makeTestResultProtoMessage(
bool success, const char *errMessage) {
// TODO(b/154271547): Move this implementation into
// common/shared/send_message.cc::sendTestResultToHost
chre_test_common_TestResult testResult =
chre_test_common_TestResult_init_default;
testResult.has_code = true;
testResult.code = success ? chre_test_common_TestResult_Code_PASSED
: chre_test_common_TestResult_Code_FAILED;
if (!success && errMessage != nullptr) {
testResult.errorMessage = {.funcs = {.encode = encodeErrorMessage},
.arg = const_cast<char *>(errMessage)};
}
return testResult;
}
chre_cross_validation_wifi_WifiCapabilities
Manager::makeWifiCapabilitiesMessage(uint32_t capabilitiesFromChre) {
chre_cross_validation_wifi_WifiCapabilities capabilities;
capabilities.has_wifiCapabilities = true;
capabilities.wifiCapabilities = capabilitiesFromChre;
return capabilities;
}
void Manager::encodeAndSendMessageToHost(const void *message,
const pb_field_t *fields,
uint32_t messageType) {
size_t encodedSize;
if (!pb_get_encoded_size(&encodedSize, fields, message)) {
LOGE("Could not get encoded size of test result message");
} else {
pb_byte_t *buffer = static_cast<pb_byte_t *>(chreHeapAlloc(encodedSize));
if (buffer == nullptr) {
LOG_OOM();
} else {
pb_ostream_t ostream = pb_ostream_from_buffer(buffer, encodedSize);
if (!pb_encode(&ostream, fields, message)) {
LOGE("Could not encode data proto message");
} else if (!chreSendMessageToHostEndpoint(
static_cast<void *>(buffer), encodedSize, messageType,
mCrossValidatorState.hostEndpoint,
heapFreeMessageCallback)) {
LOGE("Could not send message to host");
}
}
}
}
void Manager::handleWifiAsyncResult(const chreAsyncResult *result) {
chre_test_common_TestResult testResult;
if (result->requestType == CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR) {
if (mStep != chre_cross_validation_wifi_Step_SETUP) {
testResult = makeTestResultProtoMessage(
false, "Received scan monitor result event when step is not SETUP");
} else {
if (result->success) {
LOGD("Wifi scan monitoring setup successfully");
testResult = makeTestResultProtoMessage(true);
} else {
LOGE("Wifi scan monitoring setup failed async w/ error code %" PRIu8
".",
result->errorCode);
testResult = makeTestResultProtoMessage(
false, "Wifi scan monitoring setup failed async.");
}
}
} else {
testResult = makeTestResultProtoMessage(
false, "Unknown chre async result type received");
}
encodeAndSendMessageToHost(
static_cast<void *>(&testResult), chre_test_common_TestResult_fields,
chre_cross_validation_wifi_MessageType_STEP_RESULT);
}
} // namespace cross_validator_wifi
} // namespace chre