/*
* Copyright 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.
*/
#ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket
#define LOG_TAG "VtsDriverHalSocketServer"
#include "SocketServer.h"
#include <netinet/in.h>
#include <sys/un.h>
#include <string>
#include <VtsDriverCommUtil.h>
#include <android-base/logging.h>
#include <google/protobuf/text_format.h>
#include "test/vts/proto/ComponentSpecificationMessage.pb.h"
#include "test/vts/proto/VtsDriverControlMessage.pb.h"
using namespace std;
namespace android {
namespace vts {
void VtsDriverHalSocketServer::Exit() {
LOG(INFO) << "VtsHalDriverServer::Exit";
}
int32_t VtsDriverHalSocketServer::LoadHal(const string& path, int target_class,
int target_type, float target_version,
const string& target_package,
const string& target_component_name,
const string& hw_binder_service_name,
const string& /*module_name*/) {
LOG(DEBUG) << "LoadHal(" << path << ")";
int32_t driver_id = driver_manager_->LoadTargetComponent(
path.c_str(), lib_path_, target_class, target_type, target_version,
target_package.c_str(), target_component_name.c_str(),
hw_binder_service_name.c_str());
LOG(DEBUG) << "Result: " << driver_id;
return driver_id;
}
string VtsDriverHalSocketServer::ReadSpecification(
const string& name, int target_class, int target_type, float target_version,
const string& target_package) {
ComponentSpecificationMessage msg;
driver_manager_->FindComponentSpecification(
target_class, target_type, target_version, target_package, name, &msg);
string result;
google::protobuf::TextFormat::PrintToString(msg, &result);
LOG(DEBUG) << "Result: " << result;
return result;
}
string VtsDriverHalSocketServer::Call(const string& arg) {
FunctionCallMessage* call_msg = new FunctionCallMessage();
google::protobuf::TextFormat::MergeFromString(arg, call_msg);
const string& result = driver_manager_->CallFunction(call_msg);
LOG(DEBUG) << "Result: " << result;
return result;
}
string VtsDriverHalSocketServer::GetAttribute(const string& arg) {
FunctionCallMessage* call_msg = new FunctionCallMessage();
google::protobuf::TextFormat::MergeFromString(arg, call_msg);
const string& result = driver_manager_->GetAttribute(call_msg);
LOG(DEBUG) << "Result: " << result;
return result;
}
string VtsDriverHalSocketServer::ListFunctions() const {
vts::ComponentSpecificationMessage* spec =
driver_manager_->GetComponentSpecification();
string output;
if (!spec) {
return output;
}
if (google::protobuf::TextFormat::PrintToString(*spec, &output)) {
LOG(DEBUG) << "Result: " << output;
return output;
} else {
LOG(ERROR) << "Can't serialize the interface spec message to a string.";
return output;
}
}
bool VtsDriverHalSocketServer::ProcessOneCommand() {
VtsDriverControlCommandMessage command_message;
if (!VtsSocketRecvMessage(&command_message)) return false;
// TODO: get the command type description.
LOG(DEBUG) << " command_type " << command_message.command_type();
switch (command_message.command_type()) {
case EXIT: {
Exit();
VtsDriverControlResponseMessage response_message;
response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
if (VtsSocketSendMessage(response_message)) {
LOG(INFO) << "process: " << getpid() << " exiting";
return false;
}
break;
}
case LOAD_HAL: {
LOG(INFO) << "Process command LOAD_HAL";
int32_t driver_id = LoadHal(
command_message.file_path(), command_message.target_class(),
command_message.target_type(), command_message.target_version(),
command_message.target_package(),
command_message.target_component_name(),
command_message.hw_binder_service_name(),
command_message.module_name());
VtsDriverControlResponseMessage response_message;
if (driver_id == -1) {
response_message.set_response_code(VTS_DRIVER_RESPONSE_FAIL);
} else {
response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
}
response_message.set_return_value(driver_id);
if (VtsSocketSendMessage(response_message)) return true;
break;
}
case GET_STATUS: {
int32_t result = command_message.status_type();
VtsDriverControlResponseMessage response_message;
response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
response_message.set_return_value(result);
if (VtsSocketSendMessage(response_message)) return true;
break;
}
case CALL_FUNCTION: {
LOG(INFO) << "Process command CALL_FUNCTION";
if (command_message.has_driver_caller_uid()) {
setuid(atoi(command_message.driver_caller_uid().c_str()));
}
const string& result = Call(command_message.arg());
VtsDriverControlResponseMessage response_message;
response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
response_message.set_return_message(result);
if (VtsSocketSendMessage(response_message)) return true;
break;
}
case VTS_DRIVER_COMMAND_READ_SPECIFICATION: {
LOG(INFO) << "Process command READ_SPECIFICATION";
const string& result = ReadSpecification(
command_message.module_name(), command_message.target_class(),
command_message.target_type(), command_message.target_version(),
command_message.target_package());
VtsDriverControlResponseMessage response_message;
response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
response_message.set_return_message(result);
if (VtsSocketSendMessage(response_message)) return true;
break;
}
case GET_ATTRIBUTE: {
LOG(INFO) << "Process command GET_ATTRIBUTE";
const string& result = GetAttribute(command_message.arg());
VtsDriverControlResponseMessage response_message;
response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
response_message.set_return_message(result);
if (VtsSocketSendMessage(response_message)) return true;
break;
}
case LIST_FUNCTIONS: {
LOG(INFO) << "Process command LIST_FUNCTIONS";
string result = ListFunctions();
VtsDriverControlResponseMessage response_message;
if (result.size() > 0) {
response_message.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS);
response_message.set_return_message(result.c_str());
} else {
response_message.set_response_code(VTS_DRIVER_RESPONSE_FAIL);
}
if (VtsSocketSendMessage(response_message)) return true;
break;
}
default:
break;
}
LOG(ERROR) << "Failed.";
return false;
}
// Starts to run a UNIX socket server (foreground).
int StartSocketServer(const string& socket_port_file,
VtsHalDriverManager* driver_manager,
const char* lib_path) {
int sockfd;
socklen_t clilen;
struct sockaddr_in cli_addr;
struct sockaddr_un serv_addr;
sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
LOG(ERROR) << "Can't open the socket.";
return -1;
}
unlink(socket_port_file.c_str());
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, socket_port_file.c_str());
LOG(DEBUG) << "Trying to bind (port file: " << socket_port_file << ")";
if (::bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
int error_save = errno;
LOG(ERROR) << "ERROR binding failed. errno = " << error_save << " "
<< strerror(error_save);
return -1;
}
listen(sockfd, 5);
clilen = sizeof(cli_addr);
while (true) {
LOG(DEBUG) << "Waiting for a new connection from the agent";
int newsockfd = ::accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
if (newsockfd < 0) {
LOG(ERROR) << "ERROR accept failed.";
return -1;
}
LOG(DEBUG) << "New session";
pid_t pid = fork();
if (pid == 0) { // child
close(sockfd);
LOG(DEBUG) << "Process for an agent - pid = " << getpid();
VtsDriverHalSocketServer* server =
new VtsDriverHalSocketServer(driver_manager, lib_path);
server->SetSockfd(newsockfd);
while (server->ProcessOneCommand())
;
delete server;
exit(0);
} else if (pid < 0) {
LOG(ERROR) << "Can't fork a child process to handle a session.";
return -1;
}
close(newsockfd);
}
LOG(ERROR) << "Exiting";
return 0;
}
} // namespace vts
} // namespace android
#endif