/*
* 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)
: callback_socket_name_(callback_socket_name),
hal_driver_loader_(
HalDriverLoader(spec_dir, epoch_count, callback_socket_name)) {}
DriverId VtsHalDriverManager::LoadTargetComponent(
const string& dll_file_name, const string& spec_lib_file_path,
const int component_class, const int component_type, const float version,
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, component_name,
component_type, &spec_message)) {
LOG(ERROR) << "Failed to load specification for component: "
<< GetComponentDebugMsg(component_class, component_type,
std::to_string(version), package_name,
component_name);
return kInvalidDriverId;
}
LOG(INFO) << "Loaded specification for component: "
<< GetComponentDebugMsg(component_class, component_type,
std::to_string(version), package_name,
component_name);
string driver_lib_path = "";
if (component_class == HAL_HIDL) {
driver_lib_path = GetHidlHalDriverLibName(package_name, version);
} 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,
std::to_string(version), package_name,
component_name);
return kInvalidDriverId;
} else {
LOG(INFO) << "Loaded driver for component: "
<< GetComponentDebugMsg(component_class, component_type,
std::to_string(version), 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(),
call_msg->component_type_version(),
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);
if (arg->type() == TYPE_HIDL_INTERFACE) {
string type_name = arg->predefined_type();
ComponentSpecificationMessage spec_msg;
spec_msg.set_package(GetPackageName(type_name));
spec_msg.set_component_type_version(GetVersion(type_name));
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);
}
}
}
// 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);
if (return_val->type() == 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 package_name = GetPackageName(type_name);
float version = GetVersion(type_name);
string component_name = GetComponentName(type_name);
if (!hal_driver_loader_.FindComponentSpecification(
HAL_HIDL, package_name, version, component_name, 0,
&spec_msg)) {
LOG(ERROR)
<< "Failed to load specification for generated interface :"
<< type_name;
return kErrorString;
}
string driver_lib_path =
GetHidlHalDriverLibName(package_name, version);
// 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);
}
}
}
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(),
call_msg->component_type_version(),
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 float version,
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(version);
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);
driver_id =
LoadTargetComponent("", driver_lib_path, HAL_HIDL, 0, version,
package_name, interface_name, hal_service_name);
}
return driver_id;
}
bool VtsHalDriverManager::FindComponentSpecification(
const int component_class, const int component_type, const float version,
const string& package_name, const string& component_name,
ComponentSpecificationMessage* spec_msg) {
return hal_driver_loader_.FindComponentSpecification(
component_class, package_name, version, 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()) {
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()) {
if (!cur_spec_msg.has_component_type_version() ||
cur_spec_msg.component_type_version() !=
spec_msg.component_type_version()) {
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(
stof(call_msg.component_type_version()));
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: " << call_msg.component_type_version();
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;
}
}
} // namespace vts
} // namespace android