You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

696 lines
27 KiB

/*
* Copyright (C) 2017 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 "VtsHalDriverManager"
#include "driver_manager/VtsHalDriverManager.h"
#include <iostream>
#include <string>
#include <android-base/logging.h>
#include <google/protobuf/text_format.h>
#include "utils/InterfaceSpecUtil.h"
#include "utils/StringUtil.h"
static constexpr const char* kErrorString = "error";
static constexpr const char* kVoidString = "void";
static constexpr const int kInvalidDriverId = -1;
namespace android {
namespace vts {
VtsHalDriverManager::VtsHalDriverManager(const string& spec_dir,
const int epoch_count,
const string& callback_socket_name,
VtsResourceManager* resource_manager)
: callback_socket_name_(callback_socket_name),
hal_driver_loader_(
HalDriverLoader(spec_dir, epoch_count, callback_socket_name)),
resource_manager_(resource_manager) {}
DriverId VtsHalDriverManager::LoadTargetComponent(
const string& dll_file_name, const string& spec_lib_file_path,
const int component_class, const int component_type,
const int version_major, const int version_minor,
const string& package_name, const string& component_name,
const string& hw_binder_service_name) {
LOG(DEBUG) << "dll_file_name = " << dll_file_name;
ComponentSpecificationMessage spec_message;
if (!hal_driver_loader_.FindComponentSpecification(
component_class, package_name, version_major, version_minor,
component_name, component_type, &spec_message)) {
LOG(ERROR) << "Failed to load specification for component: "
<< GetComponentDebugMsg(
component_class, component_type,
GetVersionString(version_major, version_minor),
package_name, component_name);
return kInvalidDriverId;
}
LOG(INFO) << "Loaded specification for component: "
<< GetComponentDebugMsg(
component_class, component_type,
GetVersionString(version_major, version_minor), package_name,
component_name);
string driver_lib_path = "";
if (component_class == HAL_HIDL) {
driver_lib_path =
GetHidlHalDriverLibName(package_name, version_major, version_minor);
} else {
driver_lib_path = spec_lib_file_path;
}
LOG(DEBUG) << "driver lib path " << driver_lib_path;
std::unique_ptr<DriverBase> hal_driver = nullptr;
hal_driver.reset(hal_driver_loader_.GetDriver(driver_lib_path, spec_message,
hw_binder_service_name, 0,
false, dll_file_name));
if (!hal_driver) {
LOG(ERROR) << "Can't load driver for component: "
<< GetComponentDebugMsg(
component_class, component_type,
GetVersionString(version_major, version_minor),
package_name, component_name);
return kInvalidDriverId;
} else {
LOG(INFO) << "Loaded driver for component: "
<< GetComponentDebugMsg(
component_class, component_type,
GetVersionString(version_major, version_minor),
package_name, component_name);
}
// TODO (zhuoyao): get hidl_proxy_pointer for loaded hidl hal dirver.
uint64_t interface_pt = 0;
return RegisterDriver(std::move(hal_driver), spec_message, interface_pt);
}
string VtsHalDriverManager::CallFunction(FunctionCallMessage* call_msg) {
string output = "";
DriverBase* driver = GetDriverWithCallMsg(*call_msg);
if (!driver) {
LOG(ERROR) << "can't find driver for component: "
<< GetComponentDebugMsg(
call_msg->component_class(), call_msg->component_type(),
GetVersionString(
call_msg->component_type_version_major(),
call_msg->component_type_version_minor()),
call_msg->package_name(), call_msg->component_name());
return kErrorString;
}
FunctionSpecificationMessage* api = call_msg->mutable_api();
void* result;
FunctionSpecificationMessage result_msg;
driver->FunctionCallBegin();
LOG(DEBUG) << "Call Function " << api->name();
if (call_msg->component_class() == HAL_HIDL) {
// Pre-processing if we want to call an API with an interface as argument.
for (int index = 0; index < api->arg_size(); index++) {
auto* arg = api->mutable_arg(index);
bool process_success = PreprocessHidlHalFunctionCallArgs(arg);
if (!process_success) {
LOG(ERROR) << "Error in preprocess argument index " << index;
return kErrorString;
}
}
// For Hidl HAL, use CallFunction method.
if (!driver->CallFunction(*api, callback_socket_name_, &result_msg)) {
LOG(ERROR) << "Failed to call function: " << api->DebugString();
return kErrorString;
}
} else {
if (!driver->Fuzz(api, &result, callback_socket_name_)) {
LOG(ERROR) << "Failed to call function: " << api->DebugString();
return kErrorString;
}
}
LOG(DEBUG) << "Called function " << api->name();
// set coverage data.
driver->FunctionCallEnd(api);
if (call_msg->component_class() == HAL_HIDL) {
for (int index = 0; index < result_msg.return_type_hidl_size(); index++) {
auto* return_val = result_msg.mutable_return_type_hidl(index);
bool set_success = SetHidlHalFunctionCallResults(return_val);
if (!set_success) {
LOG(ERROR) << "Error in setting return value index " << index;
return kErrorString;
}
}
google::protobuf::TextFormat::PrintToString(result_msg, &output);
return output;
} else if (call_msg->component_class() == LIB_SHARED) {
return ProcessFuncResultsForLibrary(api, result);
}
return kVoidString;
}
bool VtsHalDriverManager::VerifyResults(
DriverId id, const FunctionSpecificationMessage& expected_result,
const FunctionSpecificationMessage& actual_result) {
DriverBase* driver = GetDriverById(id);
if (!driver) {
LOG(ERROR) << "Can't find driver with id: " << id;
return false;
}
return driver->VerifyResults(expected_result, actual_result);
}
string VtsHalDriverManager::GetAttribute(FunctionCallMessage* call_msg) {
string output = "";
DriverBase* driver = GetDriverWithCallMsg(*call_msg);
if (!driver) {
LOG(ERROR) << "Can't find driver for component: "
<< GetComponentDebugMsg(
call_msg->component_class(), call_msg->component_type(),
GetVersionString(
call_msg->component_type_version_major(),
call_msg->component_type_version_minor()),
call_msg->package_name(), call_msg->component_name());
return kErrorString;
}
void* result;
FunctionSpecificationMessage* api = call_msg->mutable_api();
LOG(DEBUG) << "Get Atrribute " << api->name() << " parent_path("
<< api->parent_path() << ")";
if (!driver->GetAttribute(api, &result)) {
LOG(ERROR) << "attribute not found - todo handle more explicitly";
return kErrorString;
}
if (call_msg->component_class() == HAL_HIDL) {
api->mutable_return_type()->set_type(TYPE_STRING);
api->mutable_return_type()->mutable_string_value()->set_message(
*(string*)result);
api->mutable_return_type()->mutable_string_value()->set_length(
((string*)result)->size());
free(result);
string* output = new string();
google::protobuf::TextFormat::PrintToString(*api, output);
return *output;
} else if (call_msg->component_class() == LIB_SHARED) {
return ProcessFuncResultsForLibrary(api, result);
}
return kVoidString;
}
DriverId VtsHalDriverManager::RegisterDriver(
std::unique_ptr<DriverBase> driver,
const ComponentSpecificationMessage& spec_msg,
const uint64_t interface_pt) {
DriverId driver_id = FindDriverIdInternal(spec_msg, interface_pt, true);
if (driver_id == kInvalidDriverId) {
driver_id = hal_driver_map_.size();
hal_driver_map_.insert(make_pair(
driver_id, HalDriverInfo(spec_msg, interface_pt, std::move(driver))));
} else {
LOG(WARNING) << "Driver already exists. ";
}
return driver_id;
}
DriverBase* VtsHalDriverManager::GetDriverById(const DriverId id) {
auto res = hal_driver_map_.find(id);
if (res == hal_driver_map_.end()) {
LOG(ERROR) << "Failed to find driver info with id: " << id;
return nullptr;
}
LOG(DEBUG) << "Found driver info with id: " << id;
return res->second.driver.get();
}
uint64_t VtsHalDriverManager::GetDriverPointerById(const DriverId id) {
auto res = hal_driver_map_.find(id);
if (res == hal_driver_map_.end()) {
LOG(ERROR) << "Failed to find driver info with id: " << id;
return 0;
}
LOG(DEBUG) << "Found driver info with id: " << id;
return res->second.hidl_hal_proxy_pt;
}
DriverId VtsHalDriverManager::GetDriverIdForHidlHalInterface(
const string& package_name, const int version_major,
const int version_minor, const string& interface_name,
const string& hal_service_name) {
ComponentSpecificationMessage spec_msg;
spec_msg.set_component_class(HAL_HIDL);
spec_msg.set_package(package_name);
spec_msg.set_component_type_version_major(version_major);
spec_msg.set_component_type_version_minor(version_minor);
spec_msg.set_component_name(interface_name);
DriverId driver_id = FindDriverIdInternal(spec_msg);
if (driver_id == kInvalidDriverId) {
string driver_lib_path =
GetHidlHalDriverLibName(package_name, version_major, version_minor);
driver_id = LoadTargetComponent("", driver_lib_path, HAL_HIDL, 0,
version_major, version_minor, package_name,
interface_name, hal_service_name);
}
return driver_id;
}
bool VtsHalDriverManager::FindComponentSpecification(
const int component_class, const int component_type,
const int version_major, const int version_minor,
const string& package_name, const string& component_name,
ComponentSpecificationMessage* spec_msg) {
return hal_driver_loader_.FindComponentSpecification(
component_class, package_name, version_major, version_minor,
component_name, component_type, spec_msg);
}
ComponentSpecificationMessage*
VtsHalDriverManager::GetComponentSpecification() {
if (hal_driver_map_.empty()) {
return nullptr;
} else {
return &(hal_driver_map_.find(0)->second.spec_msg);
}
}
DriverId VtsHalDriverManager::FindDriverIdInternal(
const ComponentSpecificationMessage& spec_msg, const uint64_t interface_pt,
bool with_interface_pointer) {
if (!spec_msg.has_component_class()) {
LOG(ERROR) << "Component class not specified. ";
return kInvalidDriverId;
}
if (spec_msg.component_class() == HAL_HIDL) {
if (!spec_msg.has_package() || spec_msg.package().empty()) {
LOG(ERROR) << "Package name is required but not specified.";
return kInvalidDriverId;
}
if (!spec_msg.has_component_type_version_major() ||
!spec_msg.has_component_type_version_minor()) {
LOG(ERROR) << "Package version is required but not specified.";
return kInvalidDriverId;
}
if (!spec_msg.has_component_name() || spec_msg.component_name().empty()) {
LOG(ERROR) << "Component name is required but not specified.";
return kInvalidDriverId;
}
}
for (auto it = hal_driver_map_.begin(); it != hal_driver_map_.end(); ++it) {
ComponentSpecificationMessage cur_spec_msg = it->second.spec_msg;
if (cur_spec_msg.component_class() != spec_msg.component_class()) {
continue;
}
// If package name is specified, match package name.
if (spec_msg.has_package()) {
if (!cur_spec_msg.has_package() ||
cur_spec_msg.package() != spec_msg.package()) {
continue;
}
}
// If version is specified, match version.
if (spec_msg.has_component_type_version_major() &&
spec_msg.has_component_type_version_minor()) {
if (!cur_spec_msg.has_component_type_version_major() ||
!cur_spec_msg.has_component_type_version_minor() ||
cur_spec_msg.component_type_version_major() !=
spec_msg.component_type_version_major() ||
cur_spec_msg.component_type_version_minor() !=
spec_msg.component_type_version_minor()) {
continue;
}
}
if (spec_msg.component_class() == HAL_HIDL) {
if (cur_spec_msg.component_name() != spec_msg.component_name()) {
continue;
}
if (with_interface_pointer &&
it->second.hidl_hal_proxy_pt != interface_pt) {
continue;
}
LOG(DEBUG) << "Found hidl hal driver with id: " << it->first;
return it->first;
} else if (spec_msg.component_class() == LIB_SHARED) {
if (spec_msg.has_component_type() &&
cur_spec_msg.component_type() == spec_msg.component_type()) {
LOG(DEBUG) << "Found shared lib driver with id: " << it->first;
return it->first;
}
}
}
return kInvalidDriverId;
}
DriverBase* VtsHalDriverManager::GetDriverWithCallMsg(
const FunctionCallMessage& call_msg) {
DriverId driver_id = kInvalidDriverId;
// If call_mag contains driver_id, use that given driver id.
if (call_msg.has_hal_driver_id() &&
call_msg.hal_driver_id() != kInvalidDriverId) {
driver_id = call_msg.hal_driver_id();
} else {
// Otherwise, try to find a registed driver matches the given info. e.g.,
// package_name, version etc.
ComponentSpecificationMessage spec_msg;
spec_msg.set_component_class(call_msg.component_class());
spec_msg.set_package(call_msg.package_name());
spec_msg.set_component_type_version_major(
call_msg.component_type_version_major());
spec_msg.set_component_type_version_minor(
call_msg.component_type_version_minor());
spec_msg.set_component_name(call_msg.component_name());
driver_id = FindDriverIdInternal(spec_msg);
}
if (driver_id == kInvalidDriverId) {
LOG(ERROR) << "Can't find driver ID for package: "
<< call_msg.package_name() << " version: "
<< GetVersionString(call_msg.component_type_version_major(),
call_msg.component_type_version_minor());
return nullptr;
} else {
return GetDriverById(driver_id);
}
}
string VtsHalDriverManager::ProcessFuncResultsForLibrary(
FunctionSpecificationMessage* func_msg, void* result) {
string output = "";
if (func_msg->return_type().type() == TYPE_PREDEFINED) {
// TODO: actually handle this case.
if (result != NULL) {
// loads that interface spec and enqueues all functions.
LOG(DEBUG) << "Return type: " << func_msg->return_type().type();
} else {
LOG(ERROR) << "Return value = NULL";
}
LOG(ERROR) << "Todo: support aggregate";
google::protobuf::TextFormat::PrintToString(*func_msg, &output);
return output;
} else if (func_msg->return_type().type() == TYPE_SCALAR) {
// TODO handle when the size > 1.
// todo handle more types;
if (!strcmp(func_msg->return_type().scalar_type().c_str(), "int32_t")) {
func_msg->mutable_return_type()->mutable_scalar_value()->set_int32_t(
*((int*)(&result)));
google::protobuf::TextFormat::PrintToString(*func_msg, &output);
return output;
} else if (!strcmp(func_msg->return_type().scalar_type().c_str(),
"uint32_t")) {
func_msg->mutable_return_type()->mutable_scalar_value()->set_uint32_t(
*((int*)(&result)));
google::protobuf::TextFormat::PrintToString(*func_msg, &output);
return output;
} else if (!strcmp(func_msg->return_type().scalar_type().c_str(),
"int16_t")) {
func_msg->mutable_return_type()->mutable_scalar_value()->set_int16_t(
*((int*)(&result)));
google::protobuf::TextFormat::PrintToString(*func_msg, &output);
return output;
} else if (!strcmp(func_msg->return_type().scalar_type().c_str(),
"uint16_t")) {
google::protobuf::TextFormat::PrintToString(*func_msg, &output);
return output;
}
}
return kVoidString;
}
string VtsHalDriverManager::GetComponentDebugMsg(const int component_class,
const int component_type,
const string& version,
const string& package_name,
const string& component_name) {
if (component_class == HAL_HIDL) {
return "HIDL_HAL: " + package_name + "@" + version + "::" + component_name;
} else {
return "component_type: " + std::to_string(component_type) +
" version: " + version + " component_name: " + component_name;
}
}
bool VtsHalDriverManager::PreprocessHidlHalFunctionCallArgs(
VariableSpecificationMessage* arg) {
switch (arg->type()) {
case TYPE_ARRAY:
case TYPE_VECTOR: {
// Recursively parse each element in the vector/array.
for (int i = 0; i < arg->vector_size(); i++) {
if (!PreprocessHidlHalFunctionCallArgs(arg->mutable_vector_value(i))) {
// Bad argument, preprocess failure.
LOG(ERROR) << "Failed to preprocess vector value " << i << ".";
return false;
}
}
break;
}
case TYPE_UNION: {
// Recursively parse each union value.
for (int i = 0; i < arg->union_value_size(); i++) {
auto* union_field = arg->mutable_union_value(i);
if (!PreprocessHidlHalFunctionCallArgs(union_field)) {
// Bad argument, preprocess failure.
LOG(ERROR) << "Failed to preprocess union field \""
<< union_field->name() << "\" in union \"" << arg->name()
<< "\".";
return false;
}
}
break;
}
case TYPE_STRUCT: {
// Recursively parse each struct value.
for (int i = 0; i < arg->struct_value_size(); i++) {
auto* struct_field = arg->mutable_struct_value(i);
if (!PreprocessHidlHalFunctionCallArgs(struct_field)) {
// Bad argument, preprocess failure.
LOG(ERROR) << "Failed to preprocess struct field \""
<< struct_field->name() << "\" in struct \"" << arg->name()
<< "\".";
return false;
}
}
break;
}
case TYPE_REF: {
if (!PreprocessHidlHalFunctionCallArgs(arg->mutable_ref_value())) {
// Bad argument, preprocess failure.
LOG(ERROR) << "Failed to preprocess reference value with name \""
<< arg->name() << "\".";
return false;
}
break;
}
case TYPE_HIDL_INTERFACE: {
string type_name = arg->predefined_type();
ComponentSpecificationMessage spec_msg;
string version_str = GetVersion(type_name);
int version_major = GetVersionMajor(version_str, true);
int version_minor = GetVersionMinor(version_str, true);
spec_msg.set_package(GetPackageName(type_name));
spec_msg.set_component_type_version_major(version_major);
spec_msg.set_component_type_version_minor(version_minor);
spec_msg.set_component_name(GetComponentName(type_name));
DriverId driver_id = FindDriverIdInternal(spec_msg);
// If found a registered driver for the interface, set the pointer in
// the arg proto.
if (driver_id != kInvalidDriverId) {
uint64_t interface_pt = GetDriverPointerById(driver_id);
arg->set_hidl_interface_pointer(interface_pt);
}
break;
}
case TYPE_FMQ_SYNC:
case TYPE_FMQ_UNSYNC: {
if (arg->fmq_value_size() == 0) {
LOG(ERROR) << "Driver manager: host side didn't specify queue "
<< "information in fmq_value field.";
return false;
}
if (arg->fmq_value(0).fmq_id() != -1) {
// Preprocess an argument that wants to use an existing FMQ.
// resource_manager returns address of hidl_memory pointer and
// driver_manager fills the address in the proto field,
// which can be read by HAL driver.
size_t descriptor_addr;
bool success =
resource_manager_->GetQueueDescAddress(*arg, &descriptor_addr);
if (!success) {
LOG(ERROR) << "Unable to find queue descriptor for queue with id "
<< arg->fmq_value(0).fmq_id();
return false;
}
arg->mutable_fmq_value(0)->set_fmq_desc_address(descriptor_addr);
}
break;
}
case TYPE_HIDL_MEMORY: {
if (arg->hidl_memory_value().mem_id() != -1) {
// Preprocess an argument that wants to use an existing hidl_memory.
// resource_manager returns the address of the hidl_memory pointer,
// and driver_manager fills the address in the proto field,
// which can be read by vtsc.
size_t hidl_mem_address;
bool success =
resource_manager_->GetHidlMemoryAddress(*arg, &hidl_mem_address);
if (!success) {
LOG(ERROR) << "Unable to find hidl_memory with id "
<< arg->hidl_memory_value().mem_id();
return false;
}
arg->mutable_hidl_memory_value()->set_hidl_mem_address(
hidl_mem_address);
}
break;
}
case TYPE_HANDLE: {
if (arg->handle_value().handle_id() != -1) {
// Preprocess an argument that wants to use an existing hidl_handle.
// resource_manager returns the address of the hidl_memory pointer,
// and driver_manager fills the address in the proto field,
// which can be read by vtsc.
size_t hidl_handle_address;
bool success =
resource_manager_->GetHidlHandleAddress(*arg, &hidl_handle_address);
if (!success) {
LOG(ERROR) << "Unable to find hidl_handle with id "
<< arg->handle_value().handle_id();
return false;
}
arg->mutable_handle_value()->set_hidl_handle_address(
hidl_handle_address);
}
break;
}
default:
break;
}
return true;
}
bool VtsHalDriverManager::SetHidlHalFunctionCallResults(
VariableSpecificationMessage* return_val) {
switch (return_val->type()) {
case TYPE_ARRAY:
case TYPE_VECTOR: {
// Recursively set each element in the vector/array.
for (int i = 0; i < return_val->vector_size(); i++) {
if (!SetHidlHalFunctionCallResults(
return_val->mutable_vector_value(i))) {
// Failed to set recursive return value.
LOG(ERROR) << "Failed to set vector value " << i << ".";
return false;
}
}
break;
}
case TYPE_UNION: {
// Recursively set each field.
for (int i = 0; i < return_val->union_value_size(); i++) {
auto* union_field = return_val->mutable_union_value(i);
if (!SetHidlHalFunctionCallResults(union_field)) {
// Failed to set recursive return value.
LOG(ERROR) << "Failed to set union field \"" << union_field->name()
<< "\" in union \"" << return_val->name() << "\".";
return false;
}
}
break;
}
case TYPE_STRUCT: {
// Recursively set each field.
for (int i = 0; i < return_val->struct_value_size(); i++) {
auto* struct_field = return_val->mutable_struct_value(i);
if (!SetHidlHalFunctionCallResults(struct_field)) {
// Failed to set recursive return value.
LOG(ERROR) << "Failed to set struct field \"" << struct_field->name()
<< "\" in struct \"" << return_val->name() << "\".";
return false;
}
}
break;
}
case TYPE_REF: {
if (!SetHidlHalFunctionCallResults(return_val->mutable_ref_value())) {
// Failed to set recursive return value.
LOG(ERROR) << "Failed to set reference value for \""
<< return_val->name() << "\".";
return false;
}
break;
}
case TYPE_HIDL_INTERFACE: {
if (return_val->hidl_interface_pointer() != 0) {
string type_name = return_val->predefined_type();
uint64_t interface_pt = return_val->hidl_interface_pointer();
std::unique_ptr<DriverBase> driver;
ComponentSpecificationMessage spec_msg;
string version_str = GetVersion(type_name);
int version_major = GetVersionMajor(version_str, true);
int version_minor = GetVersionMinor(version_str, true);
string package_name = GetPackageName(type_name);
string component_name = GetComponentName(type_name);
if (!hal_driver_loader_.FindComponentSpecification(
HAL_HIDL, package_name, version_major, version_minor,
component_name, 0, &spec_msg)) {
LOG(ERROR) << "Failed to load specification for generated interface :"
<< type_name;
return false;
}
string driver_lib_path =
GetHidlHalDriverLibName(package_name, version_major, version_minor);
// TODO(zhuoyao): figure out a way to get the service_name.
string hw_binder_service_name = "default";
driver.reset(hal_driver_loader_.GetDriver(driver_lib_path, spec_msg,
hw_binder_service_name,
interface_pt, true, ""));
int32_t driver_id =
RegisterDriver(std::move(driver), spec_msg, interface_pt);
return_val->set_hidl_interface_id(driver_id);
} else {
// in case of generated nullptr, set the driver_id to -1.
return_val->set_hidl_interface_id(-1);
}
break;
}
case TYPE_FMQ_SYNC:
case TYPE_FMQ_UNSYNC: {
// Tell resource_manager to register a new FMQ.
int new_queue_id = resource_manager_->RegisterFmq(*return_val);
return_val->mutable_fmq_value(0)->set_fmq_id(new_queue_id);
break;
}
case TYPE_HIDL_MEMORY: {
// Tell resource_manager to register the new memory object.
int new_mem_id = resource_manager_->RegisterHidlMemory(*return_val);
return_val->mutable_hidl_memory_value()->set_mem_id(new_mem_id);
break;
}
case TYPE_HANDLE: {
// Tell resource_manager to register the new handle object.
int new_handle_id = resource_manager_->RegisterHidlHandle(*return_val);
return_val->mutable_handle_value()->set_handle_id(new_handle_id);
break;
}
default:
break;
}
return true;
}
} // namespace vts
} // namespace android