v811_spc009/test/vts/drivers/resource/resource_manager/VtsResourceManager.cpp

761 lines
30 KiB

//
// Copyright 2018 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.
//
#define LOG_TAG "VtsResourceManager"
#include "resource_manager/VtsResourceManager.h"
#include <dlfcn.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <regex>
#include "test/vts/proto/ComponentSpecificationMessage.pb.h"
#include "test/vts/proto/VtsResourceControllerMessage.pb.h"
using android::hardware::kSynchronizedReadWrite;
using android::hardware::kUnsynchronizedWrite;
using namespace std;
namespace android {
namespace vts {
VtsResourceManager::VtsResourceManager() {}
VtsResourceManager::~VtsResourceManager() {}
void VtsResourceManager::ProcessHidlHandleCommand(
const HidlHandleRequestMessage& hidl_handle_request,
HidlHandleResponseMessage* hidl_handle_response) {
HidlHandleOp operation = hidl_handle_request.operation();
HandleId handle_id = hidl_handle_request.handle_id();
HandleDataValueMessage handle_info = hidl_handle_request.handle_info();
size_t read_data_size = hidl_handle_request.read_data_size();
const void* write_data =
static_cast<const void*>(hidl_handle_request.write_data().c_str());
size_t write_data_size = hidl_handle_request.write_data().length();
bool success = false;
switch (operation) {
case HANDLE_PROTO_CREATE_FILE: {
if (handle_info.fd_val().size() == 0) {
LOG(ERROR) << "No files to open.";
break;
}
// TODO: currently only support opening a single file.
// Support any file descriptor type in the future.
FdMessage file_desc_info = handle_info.fd_val(0);
if (file_desc_info.type() != FILE_TYPE) {
LOG(ERROR) << "Currently only support file type.";
break;
}
string filepath = file_desc_info.file_name();
int flag;
int mode = 0;
// Translate the mode into C++ flags and modes.
if (file_desc_info.file_mode_str() == "r" ||
file_desc_info.file_mode_str() == "rb") {
flag = O_RDONLY;
} else if (file_desc_info.file_mode_str() == "w" ||
file_desc_info.file_mode_str() == "wb") {
flag = O_WRONLY | O_CREAT | O_TRUNC;
mode = S_IRWXU; // User has the right to read/write/execute.
} else if (file_desc_info.file_mode_str() == "a" ||
file_desc_info.file_mode_str() == "ab") {
flag = O_WRONLY | O_CREAT | O_APPEND;
mode = S_IRWXU;
} else if (file_desc_info.file_mode_str() == "r+" ||
file_desc_info.file_mode_str() == "rb+" ||
file_desc_info.file_mode_str() == "r+b") {
flag = O_RDWR;
} else if (file_desc_info.file_mode_str() == "w+" ||
file_desc_info.file_mode_str() == "wb+" ||
file_desc_info.file_mode_str() == "w+b") {
flag = O_RDWR | O_CREAT | O_TRUNC;
mode = S_IRWXU;
} else if (file_desc_info.file_mode_str() == "a+" ||
file_desc_info.file_mode_str() == "ab+" ||
file_desc_info.file_mode_str() == "a+b") {
flag = O_RDWR | O_CREAT | O_APPEND;
mode = S_IRWXU;
} else if (file_desc_info.file_mode_str() == "x" ||
file_desc_info.file_mode_str() == "x+") {
struct stat buffer;
if (stat(filepath.c_str(), &buffer) == 0) {
LOG(ERROR) << "Host side creates a file with mode x, "
<< "but file already exists";
break;
}
flag = O_CREAT;
mode = S_IRWXU;
if (file_desc_info.file_mode_str() == "x+") {
flag |= O_RDWR;
} else {
flag |= O_WRONLY;
}
} else {
LOG(ERROR) << "Unknown file mode.";
break;
}
// Convert repeated int field into vector.
vector<int> int_data(write_data_size);
transform(handle_info.int_val().cbegin(), handle_info.int_val().cend(),
int_data.begin(), [](const int& item) { return item; });
// Call API on hidl_handle driver to create a file handle.
int new_handle_id =
hidl_handle_driver_.CreateFileHandle(filepath, flag, mode, int_data);
hidl_handle_response->set_new_handle_id(new_handle_id);
success = new_handle_id != -1;
break;
}
case HANDLE_PROTO_READ_FILE: {
char read_data[read_data_size];
// Call API on hidl_handle driver to read the file.
ssize_t read_success_bytes = hidl_handle_driver_.ReadFile(
handle_id, static_cast<void*>(read_data), read_data_size);
success = read_success_bytes != -1;
hidl_handle_response->set_read_data(
string(read_data, read_success_bytes));
break;
}
case HANDLE_PROTO_WRITE_FILE: {
// Call API on hidl_handle driver to write to the file.
ssize_t write_success_bytes =
hidl_handle_driver_.WriteFile(handle_id, write_data, write_data_size);
success = write_success_bytes != -1;
hidl_handle_response->set_write_data_size(write_success_bytes);
break;
}
case HANDLE_PROTO_DELETE: {
// Call API on hidl_handle driver to unregister the handle object.
success = hidl_handle_driver_.UnregisterHidlHandle(handle_id);
break;
}
default:
LOG(ERROR) << "Unknown operation.";
break;
}
hidl_handle_response->set_success(success);
}
int VtsResourceManager::RegisterHidlHandle(
const VariableSpecificationMessage& hidl_handle_msg) {
size_t hidl_handle_address =
hidl_handle_msg.handle_value().hidl_handle_address();
if (hidl_handle_address == 0) {
LOG(ERROR) << "Invalid hidl_handle address."
<< "HAL driver either didn't set the address or "
<< "set a null pointer.";
return -1; // check for null pointer
}
return hidl_handle_driver_.RegisterHidlHandle(hidl_handle_address);
}
bool VtsResourceManager::GetHidlHandleAddress(
const VariableSpecificationMessage& hidl_handle_msg, size_t* result) {
int handle_id = hidl_handle_msg.handle_value().handle_id();
bool success = hidl_handle_driver_.GetHidlHandleAddress(handle_id, result);
return success;
}
void VtsResourceManager::ProcessHidlMemoryCommand(
const HidlMemoryRequestMessage& hidl_memory_request,
HidlMemoryResponseMessage* hidl_memory_response) {
size_t mem_size = hidl_memory_request.mem_size();
int mem_id = hidl_memory_request.mem_id();
uint64_t start = hidl_memory_request.start();
uint64_t length = hidl_memory_request.length();
const string& write_data = hidl_memory_request.write_data();
bool success = false;
switch (hidl_memory_request.operation()) {
case MEM_PROTO_ALLOCATE: {
int new_mem_id = hidl_memory_driver_.Allocate(mem_size);
hidl_memory_response->set_new_mem_id(new_mem_id);
success = new_mem_id != -1;
break;
}
case MEM_PROTO_START_READ: {
success = hidl_memory_driver_.Read(mem_id);
break;
}
case MEM_PROTO_START_READ_RANGE: {
success = hidl_memory_driver_.ReadRange(mem_id, start, length);
break;
}
case MEM_PROTO_START_UPDATE: {
success = hidl_memory_driver_.Update(mem_id);
break;
}
case MEM_PROTO_START_UPDATE_RANGE: {
success = hidl_memory_driver_.UpdateRange(mem_id, start, length);
break;
}
case MEM_PROTO_UPDATE_BYTES: {
success = hidl_memory_driver_.UpdateBytes(mem_id, write_data.c_str(),
length, start);
break;
}
case MEM_PROTO_READ_BYTES: {
char read_data[length];
success = hidl_memory_driver_.ReadBytes(mem_id, read_data, length, start);
hidl_memory_response->set_read_data(string(read_data, length));
break;
}
case MEM_PROTO_COMMIT: {
success = hidl_memory_driver_.Commit(mem_id);
break;
}
case MEM_PROTO_GET_SIZE: {
size_t result_mem_size;
success = hidl_memory_driver_.GetSize(mem_id, &result_mem_size);
hidl_memory_response->set_mem_size(result_mem_size);
break;
}
default:
LOG(ERROR) << "unknown operation in hidl_memory_driver.";
break;
}
hidl_memory_response->set_success(success);
}
int VtsResourceManager::RegisterHidlMemory(
const VariableSpecificationMessage& hidl_memory_msg) {
size_t hidl_mem_address =
hidl_memory_msg.hidl_memory_value().hidl_mem_address();
if (hidl_mem_address == 0) {
LOG(ERROR) << "Resource manager: invalid hidl_memory address."
<< "HAL driver either didn't set the address or "
<< "set a null pointer.";
return -1; // check for null pointer
}
return hidl_memory_driver_.RegisterHidlMemory(hidl_mem_address);
}
bool VtsResourceManager::GetHidlMemoryAddress(
const VariableSpecificationMessage& hidl_memory_msg, size_t* result) {
int mem_id = hidl_memory_msg.hidl_memory_value().mem_id();
bool success = hidl_memory_driver_.GetHidlMemoryAddress(mem_id, result);
return success;
}
void VtsResourceManager::ProcessFmqCommand(const FmqRequestMessage& fmq_request,
FmqResponseMessage* fmq_response) {
const string& data_type = fmq_request.data_type();
// Find the correct function with template to process FMQ operation.
auto iterator = func_map_.find(data_type);
if (iterator == func_map_.end()) { // queue not found
LOG(ERROR) << "Resource manager: current FMQ driver doesn't support type "
<< data_type;
fmq_response->set_success(false);
} else {
(this->*(iterator->second))(fmq_request, fmq_response);
}
}
int VtsResourceManager::RegisterFmq(
const VariableSpecificationMessage& queue_msg) {
size_t queue_desc_addr = queue_msg.fmq_value(0).fmq_desc_address();
if (queue_desc_addr == 0) {
LOG(ERROR)
<< "Resource manager: invalid queue descriptor address."
<< "HAL driver either didn't set the address or set a null pointer.";
return -1; // check for null pointer
}
FmqRequestMessage fmq_request;
FmqResponseMessage fmq_response;
fmq_request.set_operation(FMQ_CREATE);
fmq_request.set_sync(queue_msg.type() == TYPE_FMQ_SYNC);
// TODO: support user-defined types in the future, only support scalar types
// for now.
fmq_request.set_data_type(queue_msg.fmq_value(0).scalar_type());
fmq_request.set_queue_desc_addr(queue_desc_addr);
ProcessFmqCommand(fmq_request, &fmq_response);
return fmq_response.queue_id();
}
bool VtsResourceManager::GetQueueDescAddress(
const VariableSpecificationMessage& queue_msg, size_t* result) {
FmqRequestMessage fmq_request;
FmqResponseMessage fmq_response;
fmq_request.set_operation(FMQ_GET_DESC_ADDR);
fmq_request.set_sync(queue_msg.type() == TYPE_FMQ_SYNC);
// TODO: support user-defined types in the future, only support scalar types
// for now.
fmq_request.set_data_type(queue_msg.fmq_value(0).scalar_type());
fmq_request.set_queue_id(queue_msg.fmq_value(0).fmq_id());
ProcessFmqCommand(fmq_request, &fmq_response);
bool success = fmq_response.success();
*result = fmq_response.sizet_return_val();
return success;
}
template <typename T>
void VtsResourceManager::ProcessFmqCommandWithType(
const FmqRequestMessage& fmq_request, FmqResponseMessage* fmq_response) {
// Infers queue flavor and calls the internal method.
if (fmq_request.sync()) {
ProcessFmqCommandInternal<T, kSynchronizedReadWrite>(fmq_request,
fmq_response);
} else {
ProcessFmqCommandInternal<T, kUnsynchronizedWrite>(fmq_request,
fmq_response);
}
}
template <typename T, hardware::MQFlavor flavor>
void VtsResourceManager::ProcessFmqCommandInternal(
const FmqRequestMessage& fmq_request, FmqResponseMessage* fmq_response) {
const string& data_type = fmq_request.data_type();
int queue_id = fmq_request.queue_id();
size_t queue_size = fmq_request.queue_size();
bool blocking = fmq_request.blocking();
bool reset_pointers = fmq_request.reset_pointers();
size_t write_data_size = fmq_request.write_data_size();
T write_data[write_data_size];
size_t read_data_size = fmq_request.read_data_size();
T read_data[read_data_size];
size_t queue_desc_addr = fmq_request.queue_desc_addr();
int64_t time_out_nanos = fmq_request.time_out_nanos();
// TODO: The three variables below are manually created.
// In the future, get these from host side when we support long-form
// blocking from host side.
uint32_t read_notification = 0;
uint32_t write_notification = 0;
atomic<uint32_t> event_flag_word;
bool success = false;
size_t sizet_result;
switch (fmq_request.operation()) {
case FMQ_CREATE: {
int new_queue_id = -1;
if (queue_id == -1) {
if (queue_desc_addr == 0) {
new_queue_id =
fmq_driver_.CreateFmq<T, flavor>(data_type, queue_size, blocking);
} else {
new_queue_id =
fmq_driver_.CreateFmq<T, flavor>(data_type, queue_desc_addr);
}
} else {
new_queue_id = fmq_driver_.CreateFmq<T, flavor>(data_type, queue_id,
reset_pointers);
}
fmq_response->set_queue_id(new_queue_id);
success = new_queue_id != -1;
break;
}
case FMQ_READ: {
success = fmq_driver_.ReadFmq<T, flavor>(data_type, queue_id, read_data,
read_data_size);
if (!FmqCpp2Proto<T>(fmq_response, data_type, read_data,
read_data_size)) {
LOG(ERROR) << "Resource manager: failed to convert C++ type into "
<< "protobuf message for type " << data_type;
break;
}
break;
}
case FMQ_READ_BLOCKING: {
success = fmq_driver_.ReadFmqBlocking<T, flavor>(
data_type, queue_id, read_data, read_data_size, time_out_nanos);
if (!FmqCpp2Proto<T>(fmq_response, data_type, read_data,
read_data_size)) {
LOG(ERROR) << "Resource manager: failed to convert C++ type into "
<< "protobuf message for type " << data_type;
break;
}
break;
}
case FMQ_READ_BLOCKING_LONG: {
// TODO: implement a meaningful long-form blocking mechanism
// Currently passing a test event flag word.
success = fmq_driver_.ReadFmqBlocking<T, flavor>(
data_type, queue_id, read_data, read_data_size, read_notification,
write_notification, time_out_nanos, &event_flag_word);
if (!FmqCpp2Proto<T>(fmq_response, data_type, read_data,
read_data_size)) {
LOG(ERROR) << "Resource manager: failed to convert C++ type into "
<< "protobuf message for type " << data_type;
break;
}
break;
}
case FMQ_WRITE: {
if (!FmqProto2Cpp<T>(fmq_request, write_data, write_data_size)) {
LOG(ERROR) << "Resource manager: failed to convert protobuf message "
<< "into C++ types for type " << data_type;
break;
}
success = fmq_driver_.WriteFmq<T, flavor>(data_type, queue_id, write_data,
write_data_size);
break;
}
case FMQ_WRITE_BLOCKING: {
if (!FmqProto2Cpp<T>(fmq_request, write_data, write_data_size)) {
LOG(ERROR) << "Resource manager: failed to convert protobuf message "
<< "into C++ types for type " << data_type;
break;
}
success = fmq_driver_.WriteFmqBlocking<T, flavor>(
data_type, queue_id, write_data, write_data_size, time_out_nanos);
break;
}
case FMQ_WRITE_BLOCKING_LONG: {
// TODO: implement a meaningful long-form blocking mechanism
// Currently passing a test event flag word.
if (!FmqProto2Cpp<T>(fmq_request, write_data, write_data_size)) {
LOG(ERROR) << "Resource manager: failed to convert protobuf message "
<< "into C++ types for type " << data_type;
break;
}
success = fmq_driver_.WriteFmqBlocking<T, flavor>(
data_type, queue_id, write_data, write_data_size, read_notification,
write_notification, time_out_nanos, &event_flag_word);
break;
}
case FMQ_AVAILABLE_WRITE: {
success = fmq_driver_.AvailableToWrite<T, flavor>(data_type, queue_id,
&sizet_result);
fmq_response->set_sizet_return_val(sizet_result);
break;
}
case FMQ_AVAILABLE_READ: {
success = fmq_driver_.AvailableToRead<T, flavor>(data_type, queue_id,
&sizet_result);
fmq_response->set_sizet_return_val(sizet_result);
break;
}
case FMQ_GET_QUANTUM_SIZE: {
success = fmq_driver_.GetQuantumSize<T, flavor>(data_type, queue_id,
&sizet_result);
fmq_response->set_sizet_return_val(sizet_result);
break;
}
case FMQ_GET_QUANTUM_COUNT: {
success = fmq_driver_.GetQuantumCount<T, flavor>(data_type, queue_id,
&sizet_result);
fmq_response->set_sizet_return_val(sizet_result);
break;
}
case FMQ_IS_VALID: {
success = fmq_driver_.IsValid<T, flavor>(data_type, queue_id);
break;
}
case FMQ_GET_DESC_ADDR: {
success = fmq_driver_.GetQueueDescAddress<T, flavor>(data_type, queue_id,
&sizet_result);
fmq_response->set_sizet_return_val(sizet_result);
break;
}
default:
LOG(ERROR) << "Resource manager: Unsupported FMQ operation.";
}
fmq_response->set_success(success);
}
template <typename T>
bool VtsResourceManager::FmqProto2Cpp(const FmqRequestMessage& fmq_request,
T* write_data, size_t write_data_size) {
const string& data_type = fmq_request.data_type();
// Read from different proto fields based on type.
if (data_type == "int8_t") {
int8_t* convert_data = reinterpret_cast<int8_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = (fmq_request.write_data(i).scalar_value().int8_t());
}
} else if (data_type == "uint8_t") {
uint8_t* convert_data = reinterpret_cast<uint8_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().uint8_t();
}
} else if (data_type == "int16_t") {
int16_t* convert_data = reinterpret_cast<int16_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().int16_t();
}
} else if (data_type == "uint16_t") {
uint16_t* convert_data = reinterpret_cast<uint16_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().uint16_t();
}
} else if (data_type == "int32_t") {
int32_t* convert_data = reinterpret_cast<int32_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().int32_t();
}
} else if (data_type == "uint32_t") {
uint32_t* convert_data = reinterpret_cast<uint32_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().uint32_t();
}
} else if (data_type == "int64_t") {
int64_t* convert_data = reinterpret_cast<int64_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().int64_t();
}
} else if (data_type == "uint64_t") {
uint64_t* convert_data = reinterpret_cast<uint64_t*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().uint64_t();
}
} else if (data_type == "float_t") {
float* convert_data = reinterpret_cast<float*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().float_t();
}
} else if (data_type == "double_t") {
double* convert_data = reinterpret_cast<double*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().double_t();
}
} else if (data_type == "bool_t") {
bool* convert_data = reinterpret_cast<bool*>(write_data);
for (int i = 0; i < write_data_size; i++) {
convert_data[i] = fmq_request.write_data(i).scalar_value().bool_t();
}
} else {
// Encounter a predefined type in HAL service.
LOG(INFO) << "Resource manager: detected host side specifies a "
<< "predefined type.";
void* shared_lib_obj = LoadSharedLibFromTypeName(data_type);
// Locate the symbol for the translation function.
typedef void (*parse_fn)(const VariableSpecificationMessage&, T*,
const string&);
parse_fn parser =
(parse_fn)(GetTranslationFuncPtr(shared_lib_obj, data_type, true));
if (!parser) return false; // Error logged in helper function.
// Parse the data from protobuf to C++.
for (int i = 0; i < write_data_size; i++) {
(*parser)(fmq_request.write_data(i), &write_data[i], "");
}
dlclose(shared_lib_obj);
}
return true;
}
// TODO: support user-defined types, only support primitive types now.
template <typename T>
bool VtsResourceManager::FmqCpp2Proto(FmqResponseMessage* fmq_response,
const string& data_type, T* read_data,
size_t read_data_size) {
fmq_response->clear_read_data();
// Write to different proto fields based on type.
if (data_type == "int8_t") {
int8_t* convert_data = reinterpret_cast<int8_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_int8_t(convert_data[i]);
}
} else if (data_type == "uint8_t") {
uint8_t* convert_data = reinterpret_cast<uint8_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_uint8_t(convert_data[i]);
}
} else if (data_type == "int16_t") {
int16_t* convert_data = reinterpret_cast<int16_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_int16_t(convert_data[i]);
}
} else if (data_type == "uint16_t") {
uint16_t* convert_data = reinterpret_cast<uint16_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_uint16_t(convert_data[i]);
}
} else if (data_type == "int32_t") {
int32_t* convert_data = reinterpret_cast<int32_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_int32_t(convert_data[i]);
}
} else if (data_type == "uint32_t") {
uint32_t* convert_data = reinterpret_cast<uint32_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_uint32_t(convert_data[i]);
}
} else if (data_type == "int64_t") {
int64_t* convert_data = reinterpret_cast<int64_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_int64_t(convert_data[i]);
}
} else if (data_type == "uint64_t") {
uint64_t* convert_data = reinterpret_cast<uint64_t*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_uint64_t(convert_data[i]);
}
} else if (data_type == "float_t") {
float* convert_data = reinterpret_cast<float*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_float_t(convert_data[i]);
}
} else if (data_type == "double_t") {
double* convert_data = reinterpret_cast<double*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_double_t(convert_data[i]);
}
} else if (data_type == "bool_t") {
bool* convert_data = reinterpret_cast<bool*>(read_data);
for (size_t i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
item->set_type(TYPE_SCALAR);
item->set_scalar_type(data_type);
(item->mutable_scalar_value())->set_bool_t(convert_data[i]);
}
} else {
// Encounter a predefined type in HAL service.
LOG(INFO) << "Resource manager: detected host side specifies a "
<< "predefined type.";
void* shared_lib_obj = LoadSharedLibFromTypeName(data_type);
if (!shared_lib_obj) return false;
// Locate the symbol for the translation function.
typedef void (*set_result_fn)(VariableSpecificationMessage*, T);
set_result_fn parser =
(set_result_fn)(GetTranslationFuncPtr(shared_lib_obj, data_type, 0));
if (!parser) return false; // Error logged in helper function.
// Parse the data from C++ to protobuf.
for (int i = 0; i < read_data_size; i++) {
VariableSpecificationMessage* item = fmq_response->add_read_data();
(*parser)(item, read_data[i]);
}
dlclose(shared_lib_obj);
}
return true;
}
void* VtsResourceManager::LoadSharedLibFromTypeName(const string& data_type) {
// Base path.
// TODO: Consider determining the path and bitness by passing a field
// in the protobuf message.
string shared_lib_path = "/data/local/tmp/64/";
// Start searching after the first ::
size_t curr_index = 0;
size_t next_index;
bool success = false;
regex version_regex("V[0-9]+_[0-9]+");
const string split_str = "::";
while ((next_index = data_type.find(split_str, curr_index)) != string::npos) {
if (curr_index == next_index) {
// No character between the current :: and the next ::
// Likely it is the first :: in the type name.
curr_index = next_index + split_str.length();
continue;
}
string curr_string = data_type.substr(curr_index, next_index - curr_index);
// Check if it is a version, e.g. V4_0.
if (regex_match(curr_string, version_regex)) {
size_t length = shared_lib_path.length();
// Change _ into ., e.g. V4_0 to V4.0.
size_t separator = curr_string.find("_");
curr_string.replace(separator, 1, ".");
// Use @ before version.
shared_lib_path.replace(length - 1, 1, "@");
// Exclude V in the front.
shared_lib_path += curr_string.substr(1);
success = true;
break;
} else {
shared_lib_path += curr_string + ".";
}
// Start searching from the next ::
curr_index = next_index + split_str.length();
}
// Failed to parse the shared library name from type name.
if (!success) return nullptr;
shared_lib_path += "-vts.driver.so";
// Load the shared library that contains translation functions.
void* shared_lib_obj = dlopen(shared_lib_path.c_str(), RTLD_LAZY);
if (!shared_lib_obj) {
LOG(ERROR) << "Resource manager: failed to load shared lib "
<< shared_lib_path << " for type " << data_type;
return nullptr;
}
LOG(INFO) << "Resource manager: successfully loaded shared library "
<< shared_lib_path;
return shared_lib_obj;
}
void* VtsResourceManager::GetTranslationFuncPtr(void* shared_lib_obj,
const string& data_type,
bool is_proto_to_cpp) {
string translation_func_name = data_type;
// Replace all :: with __.
// TODO: there might be a special case where part of the type name involves
// a single :. Consider fixing this in the future.
replace(translation_func_name.begin(), translation_func_name.end(), ':', '_');
void* func_ptr = nullptr;
if (is_proto_to_cpp) {
func_ptr =
dlsym(shared_lib_obj, ("MessageTo" + translation_func_name).c_str());
if (!func_ptr) {
LOG(ERROR) << "Resource manager: failed to load function name "
<< "MessageTo" << translation_func_name << " or "
<< "EnumValue" << translation_func_name
<< " to parse protobuf message into C++ type.";
}
} else {
func_ptr =
dlsym(shared_lib_obj, ("SetResult" + translation_func_name).c_str());
if (!func_ptr) {
LOG(ERROR) << "Resource manager: failed to load the function name "
<< "SetResult" << translation_func_name
<< " to parse C++ type into protobuf message.";
}
}
return func_ptr;
}
} // namespace vts
} // namespace android