blob: d767168087a20c86ae3e6bad2dfe2f04f29963d0 [file] [log] [blame]
/*
* Copyright (C) 2023 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_api_test_manager.h"
#include "chre/util/nanoapp/ble.h"
#include "chre/util/nanoapp/log.h"
#include "chre/util/nanoapp/string.h"
using ::chre::copyString;
using ::chre::createBleGenericFilter;
namespace {
/**
* The following constants are defined in chre_api_test.options.
*/
constexpr uint32_t kMaxBleScanFilters = 10;
constexpr size_t kMaxNameStringBufferSize = 100;
constexpr size_t kMaxHostEndpointNameBufferSize = 51;
constexpr size_t kMaxHostEndpointTagBufferSize = 51;
} // namespace
bool ChreApiTestService::validateInputAndCallChreBleGetCapabilities(
const google_protobuf_Empty & /* request */,
chre_rpc_Capabilities &response) {
response.capabilities = chreBleGetCapabilities();
LOGD("ChreBleGetCapabilities: capabilities: %" PRIu32, response.capabilities);
return true;
}
bool ChreApiTestService::validateInputAndCallChreBleGetFilterCapabilities(
const google_protobuf_Empty & /* request */,
chre_rpc_Capabilities &response) {
response.capabilities = chreBleGetFilterCapabilities();
LOGD("ChreBleGetFilterCapabilities: capabilities: %" PRIu32,
response.capabilities);
return true;
}
bool ChreApiTestService::validateInputAndCallChreBleStartScanAsync(
const chre_rpc_ChreBleStartScanAsyncInput &request,
chre_rpc_Status &response) {
if (request.mode < _chre_rpc_ChreBleScanMode_MIN ||
request.mode > _chre_rpc_ChreBleScanMode_MAX ||
request.mode == chre_rpc_ChreBleScanMode_INVALID) {
LOGE("ChreBleStartScanAsync: invalid mode");
return false;
}
if (!request.hasFilter) {
chreBleScanMode mode = static_cast<chreBleScanMode>(request.mode);
response.status =
chreBleStartScanAsync(mode, request.reportDelayMs, nullptr);
LOGD("ChreBleStartScanAsync: mode: %s, reportDelayMs: %" PRIu32
", filter: nullptr, status: %s",
mode == CHRE_BLE_SCAN_MODE_BACKGROUND
? "background"
: (mode == CHRE_BLE_SCAN_MODE_FOREGROUND ? "foreground"
: "aggressive"),
request.reportDelayMs, response.status ? "true" : "false");
return true;
}
if (request.filter.rssiThreshold < std::numeric_limits<int8_t>::min() ||
request.filter.rssiThreshold > std::numeric_limits<int8_t>::max()) {
LOGE("ChreBleStartScanAsync: invalid filter.rssiThreshold");
return false;
}
if (request.filter.scanFilterCount == 0 ||
request.filter.scanFilterCount > kMaxBleScanFilters) {
LOGE("ChreBleStartScanAsync: invalid filter.scanFilterCount");
return false;
}
chreBleGenericFilter genericFilters[request.filter.scanFilterCount];
if (!validateBleScanFilters(request.filter.scanFilters, genericFilters,
request.filter.scanFilterCount)) {
return false;
}
struct chreBleScanFilter filter;
filter.rssiThreshold = request.filter.rssiThreshold;
filter.scanFilterCount = request.filter.scanFilterCount;
filter.scanFilters = genericFilters;
chreBleScanMode mode = static_cast<chreBleScanMode>(request.mode);
response.status = chreBleStartScanAsync(mode, request.reportDelayMs, &filter);
LOGD("ChreBleStartScanAsync: mode: %s, reportDelayMs: %" PRIu32
", scanFilterCount: %" PRIu32 ", status: %s",
mode == CHRE_BLE_SCAN_MODE_BACKGROUND
? "background"
: (mode == CHRE_BLE_SCAN_MODE_FOREGROUND ? "foreground"
: "aggressive"),
request.reportDelayMs, request.filter.scanFilterCount,
response.status ? "true" : "false");
return true;
}
bool ChreApiTestService::validateInputAndCallChreBleStopScanAsync(
const google_protobuf_Empty & /* request */, chre_rpc_Status &response) {
response.status = chreBleStopScanAsync();
LOGD("ChreBleStopScanAsync: status: %s", response.status ? "true" : "false");
return true;
}
bool ChreApiTestService::validateInputAndCallChreSensorFindDefault(
const chre_rpc_ChreSensorFindDefaultInput &request,
chre_rpc_ChreSensorFindDefaultOutput &response) {
if (request.sensorType > std::numeric_limits<uint8_t>::max()) {
return false;
}
uint8_t sensorType = (uint8_t)request.sensorType;
response.foundSensor =
chreSensorFindDefault(sensorType, &response.sensorHandle);
LOGD("ChreSensorFindDefault: foundSensor: %s, sensorHandle: %" PRIu32,
response.foundSensor ? "true" : "false", response.sensorHandle);
return true;
}
bool ChreApiTestService::validateInputAndCallChreGetSensorInfo(
const chre_rpc_ChreHandleInput &request,
chre_rpc_ChreGetSensorInfoOutput &response) {
struct chreSensorInfo sensorInfo;
memset(&sensorInfo, 0, sizeof(sensorInfo));
response.status = chreGetSensorInfo(request.handle, &sensorInfo);
if (response.status) {
copyString(response.sensorName, sensorInfo.sensorName,
kMaxNameStringBufferSize);
response.sensorType = sensorInfo.sensorType;
response.isOnChange = sensorInfo.isOnChange;
response.isOneShot = sensorInfo.isOneShot;
response.reportsBiasEvents = sensorInfo.reportsBiasEvents;
response.supportsPassiveMode = sensorInfo.supportsPassiveMode;
response.unusedFlags = sensorInfo.unusedFlags;
response.minInterval = sensorInfo.minInterval;
response.sensorIndex = sensorInfo.sensorIndex;
LOGD("ChreGetSensorInfo: status: true, sensorType: %" PRIu32
", isOnChange: %" PRIu32
", "
"isOneShot: %" PRIu32 ", reportsBiasEvents: %" PRIu32
", supportsPassiveMode: %" PRIu32 ", unusedFlags: %" PRIu32
", minInterval: %" PRIu64 ", sensorIndex: %" PRIu32,
response.sensorType, response.isOnChange, response.isOneShot,
response.reportsBiasEvents, response.supportsPassiveMode,
response.unusedFlags, response.minInterval, response.sensorIndex);
} else {
LOGD("ChreGetSensorInfo: status: false");
}
return true;
}
bool ChreApiTestService::validateInputAndCallChreGetSensorSamplingStatus(
const chre_rpc_ChreHandleInput &request,
chre_rpc_ChreGetSensorSamplingStatusOutput &response) {
struct chreSensorSamplingStatus samplingStatus;
memset(&samplingStatus, 0, sizeof(samplingStatus));
response.status =
chreGetSensorSamplingStatus(request.handle, &samplingStatus);
if (response.status) {
response.interval = samplingStatus.interval;
response.latency = samplingStatus.latency;
response.enabled = samplingStatus.enabled;
LOGD("ChreGetSensorSamplingStatus: status: true, interval: %" PRIu64
", latency: %" PRIu64 ", enabled: %s",
response.interval, response.latency,
response.enabled ? "true" : "false");
} else {
LOGD("ChreGetSensorSamplingStatus: status: false");
}
return true;
}
bool ChreApiTestService::validateInputAndCallChreSensorConfigure(
const chre_rpc_ChreSensorConfigureInput &request,
chre_rpc_Status &response) {
chreSensorConfigureMode mode =
static_cast<chreSensorConfigureMode>(request.mode);
response.status = chreSensorConfigure(request.sensorHandle, mode,
request.interval, request.latency);
LOGD("ChreSensorConfigure: status: %s", response.status ? "true" : "false");
return true;
}
bool ChreApiTestService::validateInputAndCallChreSensorConfigureModeOnly(
const chre_rpc_ChreSensorConfigureModeOnlyInput &request,
chre_rpc_Status &response) {
chreSensorConfigureMode mode =
static_cast<chreSensorConfigureMode>(request.mode);
response.status = chreSensorConfigureModeOnly(request.sensorHandle, mode);
LOGD("ChreSensorConfigureModeOnly: status: %s",
response.status ? "true" : "false");
return true;
}
bool ChreApiTestService::validateInputAndCallChreAudioGetSource(
const chre_rpc_ChreHandleInput &request,
chre_rpc_ChreAudioGetSourceOutput &response) {
struct chreAudioSource audioSource;
memset(&audioSource, 0, sizeof(audioSource));
response.status = chreAudioGetSource(request.handle, &audioSource);
if (response.status) {
copyString(response.name, audioSource.name, kMaxNameStringBufferSize);
response.sampleRate = audioSource.sampleRate;
response.minBufferDuration = audioSource.minBufferDuration;
response.maxBufferDuration = audioSource.maxBufferDuration;
response.format = audioSource.format;
LOGD("ChreAudioGetSource: status: true, name: %s, sampleRate %" PRIu32
", minBufferDuration: %" PRIu64 ", maxBufferDuration %" PRIu64
", format: %" PRIu32,
response.name, response.sampleRate, response.minBufferDuration,
response.maxBufferDuration, response.format);
} else {
LOGD("ChreAudioGetSource: status: false");
}
return true;
}
bool ChreApiTestService::
validateInputAndCallChreConfigureHostEndpointNotifications(
const chre_rpc_ChreConfigureHostEndpointNotificationsInput &request,
chre_rpc_Status &response) {
if (request.hostEndpointId > std::numeric_limits<uint16_t>::max()) {
LOGE("Host Endpoint Id cannot exceed max of uint16_t");
return false;
}
response.status = chreConfigureHostEndpointNotifications(
request.hostEndpointId, request.enable);
LOGD("ChreConfigureHostEndpointNotifications: status: %s",
response.status ? "true" : "false");
return true;
}
bool ChreApiTestService::validateInputAndCallChreGetHostEndpointInfo(
const chre_rpc_ChreGetHostEndpointInfoInput &request,
chre_rpc_ChreGetHostEndpointInfoOutput &response) {
if (request.hostEndpointId > std::numeric_limits<uint16_t>::max()) {
LOGE("Host Endpoint Id cannot exceed max of uint16_t");
return false;
}
struct chreHostEndpointInfo hostEndpointInfo;
memset(&hostEndpointInfo, 0, sizeof(hostEndpointInfo));
response.status =
chreGetHostEndpointInfo(request.hostEndpointId, &hostEndpointInfo);
if (response.status) {
response.hostEndpointId = hostEndpointInfo.hostEndpointId;
response.hostEndpointType = hostEndpointInfo.hostEndpointType;
response.isNameValid = hostEndpointInfo.isNameValid;
response.isTagValid = hostEndpointInfo.isTagValid;
if (hostEndpointInfo.isNameValid) {
copyString(response.endpointName, hostEndpointInfo.endpointName,
kMaxHostEndpointNameBufferSize);
} else {
memset(response.endpointName, 0, kMaxHostEndpointNameBufferSize);
}
if (hostEndpointInfo.isTagValid) {
copyString(response.endpointTag, hostEndpointInfo.endpointTag,
kMaxHostEndpointTagBufferSize);
} else {
memset(response.endpointTag, 0, kMaxHostEndpointTagBufferSize);
}
LOGD("ChreGetHostEndpointInfo: status: true, hostEndpointID: %" PRIu32
", hostEndpointType: %" PRIu32
", isNameValid: %s, isTagValid: %s, endpointName: %s, endpointTag: %s",
response.hostEndpointId, response.hostEndpointType,
response.isNameValid ? "true" : "false",
response.isTagValid ? "true" : "false", response.endpointName,
response.endpointTag);
} else {
LOGD("ChreGetHostEndpointInfo: status: false");
}
return true;
}
bool ChreApiTestService::validateBleScanFilters(
const chre_rpc_ChreBleGenericFilter *scanFilters,
chreBleGenericFilter *outputScanFilters, uint32_t scanFilterCount) {
if (scanFilters == nullptr || outputScanFilters == nullptr) {
return false;
}
for (uint32_t i = 0; i < scanFilterCount; ++i) {
const chre_rpc_ChreBleGenericFilter &scanFilter = scanFilters[i];
if (scanFilter.type > std::numeric_limits<uint8_t>::max() ||
scanFilter.length > std::numeric_limits<uint8_t>::max()) {
LOGE(
"validateBleScanFilters: invalid request.filter.scanFilters member: "
"type: %" PRIu32 " or length: %" PRIu32,
scanFilter.type, scanFilter.length);
return false;
}
if (scanFilter.data.size < scanFilter.length ||
scanFilter.mask.size < scanFilter.length) {
LOGE(
"validateBleScanFilters: invalid request.filter.scanFilters member: "
"data or mask size");
return false;
}
outputScanFilters[i] =
createBleGenericFilter(scanFilter.type, scanFilter.length,
scanFilter.data.bytes, scanFilter.mask.bytes);
}
return true;
}