/*
* Copyright (C) 2016 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 "VtsHidlHalReplayer.h"
#include <fcntl.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <string>
#include <android-base/logging.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include "VtsProfilingUtil.h"
#include "driver_base/DriverBase.h"
#include "utils/InterfaceSpecUtil.h"
#include "utils/StringUtil.h"
using namespace std;
static constexpr const char* kErrorString = "error";
static constexpr const char* kVoidString = "void";
static constexpr const int kInvalidDriverId = -1;
namespace android {
namespace vts {
void VtsHidlHalReplayer::ListTestServices(const string& trace_file) {
// Parse the trace file to get the sequence of function calls.
int fd = open(trace_file.c_str(), O_RDONLY);
if (fd < 0) {
LOG(ERROR) << "Can not open trace file: " << trace_file
<< " error: " << std::strerror(errno);
return;
}
google::protobuf::io::FileInputStream input(fd);
VtsProfilingRecord msg;
set<string> registeredHalServices;
while (readOneDelimited(&msg, &input)) {
string package_name = msg.package();
float version = msg.version();
string interface_name = msg.interface();
string service_fq_name =
GetInterfaceFQName(package_name, version, interface_name);
registeredHalServices.insert(service_fq_name);
}
for (string service : registeredHalServices) {
cout << "hal_service: " << service << endl;
}
}
bool VtsHidlHalReplayer::ReplayTrace(
const string& trace_file, map<string, string>& hal_service_instances) {
// Parse the trace file to get the sequence of function calls.
int fd = open(trace_file.c_str(), O_RDONLY);
if (fd < 0) {
LOG(ERROR) << "Can not open trace file: " << trace_file
<< "error: " << std::strerror(errno);
return false;
}
google::protobuf::io::FileInputStream input(fd);
VtsProfilingRecord call_msg;
VtsProfilingRecord expected_result_msg;
while (readOneDelimited(&call_msg, &input) &&
readOneDelimited(&expected_result_msg, &input)) {
if (call_msg.event() != InstrumentationEventType::SERVER_API_ENTRY &&
call_msg.event() != InstrumentationEventType::CLIENT_API_ENTRY &&
call_msg.event() != InstrumentationEventType::SYNC_CALLBACK_ENTRY &&
call_msg.event() != InstrumentationEventType::ASYNC_CALLBACK_ENTRY &&
call_msg.event() != InstrumentationEventType::PASSTHROUGH_ENTRY) {
LOG(WARNING) << "Expected a call message but got message with event: "
<< call_msg.event();
continue;
}
if (expected_result_msg.event() !=
InstrumentationEventType::SERVER_API_EXIT &&
expected_result_msg.event() !=
InstrumentationEventType::CLIENT_API_EXIT &&
expected_result_msg.event() !=
InstrumentationEventType::SYNC_CALLBACK_EXIT &&
expected_result_msg.event() !=
InstrumentationEventType::ASYNC_CALLBACK_EXIT &&
expected_result_msg.event() !=
InstrumentationEventType::PASSTHROUGH_EXIT) {
LOG(WARNING) << "Expected a result message but got message with event: "
<< call_msg.event();
continue;
}
string package_name = call_msg.package();
float version = call_msg.version();
string interface_name = call_msg.interface();
string instance_name =
GetInterfaceFQName(package_name, version, interface_name);
string hal_service_name = "default";
if (hal_service_instances.find(instance_name) ==
hal_service_instances.end()) {
LOG(WARNING) << "Does not find service name for " << instance_name
<< "; this could be a nested interface.";
} else {
hal_service_name = hal_service_instances[instance_name];
}
cout << "Replay function: " << call_msg.func_msg().name() << endl;
LOG(DEBUG) << "Replay function: " << call_msg.func_msg().DebugString();
int32_t driver_id = driver_manager_->GetDriverIdForHidlHalInterface(
package_name, version, interface_name, hal_service_name);
if (driver_id == kInvalidDriverId) {
LOG(ERROR) << "Couldn't get a driver base class";
return false;
}
vts::FunctionCallMessage func_call_msg;
func_call_msg.set_component_class(HAL_HIDL);
func_call_msg.set_hal_driver_id(driver_id);
*func_call_msg.mutable_api() = call_msg.func_msg();
const string& result = driver_manager_->CallFunction(&func_call_msg);
if (result == kVoidString || result == kErrorString) {
LOG(ERROR) << "Replay function fail. Failed function call: "
<< func_call_msg.DebugString();
return false;
}
vts::FunctionSpecificationMessage result_msg;
if (!google::protobuf::TextFormat::ParseFromString(result, &result_msg)) {
LOG(ERROR) << "Failed to parse result msg.";
return false;
}
if (!driver_manager_->VerifyResults(
driver_id, expected_result_msg.func_msg(), result_msg)) {
// Verification is not strict, i.e. if fail, output error message and
// continue the process.
LOG(WARNING) << "Verification fail. Expected: "
<< expected_result_msg.func_msg().DebugString()
<< " Actual: " << result_msg.DebugString();
}
call_msg.Clear();
expected_result_msg.Clear();
}
return true;
}
} // namespace vts
} // namespace android