| /* |
| * 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. |
| */ |
| #define LOG_TAG "VtsAgentRequestHandler" |
| |
| #include "AgentRequestHandler.h" |
| |
| #include <dirent.h> |
| #include <errno.h> |
| #include <sys/stat.h> |
| #include <string> |
| |
| #include <android-base/logging.h> |
| |
| #include "BinderClientToDriver.h" |
| #include "SocketClientToDriver.h" |
| #include "SocketServerForDriver.h" |
| #include "test/vts/proto/AndroidSystemControlMessage.pb.h" |
| #include "test/vts/proto/VtsDriverControlMessage.pb.h" |
| #include "test/vts/proto/VtsResourceControllerMessage.pb.h" |
| |
| using namespace std; |
| using namespace google::protobuf; |
| |
| namespace android { |
| namespace vts { |
| |
| bool AgentRequestHandler::ListHals(const RepeatedPtrField<string>& base_paths) { |
| AndroidSystemControlResponseMessage response_msg; |
| ResponseCode result = FAIL; |
| |
| for (const string& path : base_paths) { |
| LOG(DEBUG) << "open a dir " << path; |
| DIR* dp; |
| if (!(dp = opendir(path.c_str()))) { |
| LOG(ERROR) << "Error(" << errno << ") opening " << path; |
| continue; |
| } |
| |
| struct dirent* dirp; |
| int len; |
| while ((dirp = readdir(dp)) != NULL) { |
| len = strlen(dirp->d_name); |
| if (len > 3 && !strcmp(&dirp->d_name[len - 3], ".so")) { |
| string found_path = path + "/" + string(dirp->d_name); |
| LOG(INFO) << "found " << found_path; |
| response_msg.add_file_names(found_path); |
| result = SUCCESS; |
| } |
| } |
| closedir(dp); |
| } |
| response_msg.set_response_code(result); |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::SetHostInfo(const int callback_port) { |
| callback_port_ = callback_port; |
| AndroidSystemControlResponseMessage response_msg; |
| response_msg.set_response_code(SUCCESS); |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::CheckDriverService(const string& service_name, |
| bool* live) { |
| AndroidSystemControlResponseMessage response_msg; |
| |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| if (IsDriverRunning(service_name, 10)) { |
| #else // binder |
| sp<IVtsFuzzer> binder = GetBinderClient(service_name); |
| if (binder.get()) { |
| #endif |
| if (live) *live = true; |
| response_msg.set_response_code(SUCCESS); |
| response_msg.set_reason("found the service"); |
| LOG(DEBUG) << "set service_name " << service_name; |
| service_name_ = service_name; |
| } else { |
| if (live) *live = false; |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason("service not found"); |
| } |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| static const char kUnixSocketNamePrefixForCallbackServer[] = |
| "/data/local/tmp/vts_agent_callback"; |
| |
| bool AgentRequestHandler::LaunchDriverService( |
| const AndroidSystemControlCommandMessage& command_msg) { |
| int driver_type = command_msg.driver_type(); |
| const string& service_name = command_msg.service_name(); |
| const string& file_path = command_msg.file_path(); |
| int target_class = command_msg.target_class(); |
| int target_type = command_msg.target_type(); |
| int target_version_major = command_msg.target_version_major(); |
| int target_version_minor = command_msg.target_version_minor(); |
| const string& target_package = command_msg.target_package(); |
| const string& target_component_name = command_msg.target_component_name(); |
| const string& module_name = command_msg.module_name(); |
| const string& hw_binder_service_name = command_msg.hw_binder_service_name(); |
| int bits = command_msg.bits(); |
| const string& test_hal_flag = |
| command_msg.is_test_hal() ? "TREBLE_TESTING_OVERRIDE=true " : ""; |
| |
| LOG(DEBUG) << "file_path=" << file_path; |
| ResponseCode result = FAIL; |
| |
| // TODO: shall check whether there's a service with the same name and return |
| // success immediately if exists. |
| AndroidSystemControlResponseMessage response_msg; |
| |
| // deletes the service file if exists before starting to launch a driver. |
| string socket_port_flie_path = GetSocketPortFilePath(service_name); |
| struct stat file_stat; |
| if (stat(socket_port_flie_path.c_str(), &file_stat) == 0 // file exists |
| && remove(socket_port_flie_path.c_str()) == -1) { |
| LOG(ERROR) << socket_port_flie_path << " delete error"; |
| response_msg.set_reason("service file already exists."); |
| } else { |
| pid_t pid = fork(); |
| if (pid == 0) { // child |
| Close(); |
| |
| string driver_binary_path; |
| char* cmd = NULL; |
| if (driver_type == VTS_DRIVER_TYPE_HAL_CONVENTIONAL || |
| driver_type == VTS_DRIVER_TYPE_HAL_LEGACY || |
| driver_type == VTS_DRIVER_TYPE_HAL_HIDL) { |
| // TODO: check whether the port is available and handle if fails. |
| static int port = 0; |
| string callback_socket_name(kUnixSocketNamePrefixForCallbackServer); |
| callback_socket_name += to_string(port++); |
| LOG(INFO) << "callback_socket_name: " << callback_socket_name; |
| StartSocketServerForDriver(callback_socket_name, -1); |
| |
| if (bits == 32) { |
| driver_binary_path = driver_hal_binary32_; |
| } else { |
| driver_binary_path = driver_hal_binary64_; |
| } |
| size_t offset = driver_binary_path.find_last_of("/"); |
| string ld_dir_path = driver_binary_path.substr(0, offset); |
| |
| if (driver_hal_spec_dir_path_.length() < 1) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| asprintf(&cmd, |
| "%sLD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH %s " |
| "--server_socket_path=%s " |
| "--callback_socket_name=%s", |
| test_hal_flag.c_str(), ld_dir_path.c_str(), |
| driver_binary_path.c_str(), socket_port_flie_path.c_str(), |
| callback_socket_name.c_str()); |
| #else // binder |
| asprintf(&cmd, |
| "LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH %s " |
| "--service_name=%s " |
| "--callback_socket_name=%s", |
| ld_dir_path.c_str(), driver_binary_path.c_str(), |
| service_name.c_str(), callback_socket_name.c_str()); |
| #endif |
| } else { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| asprintf(&cmd, |
| "%sLD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH %s " |
| "--server_socket_path=%s " |
| "--spec_dir_path=%s --callback_socket_name=%s", |
| test_hal_flag.c_str(), ld_dir_path.c_str(), |
| driver_binary_path.c_str(), socket_port_flie_path.c_str(), |
| driver_hal_spec_dir_path_.c_str(), |
| callback_socket_name.c_str()); |
| #else // binder |
| asprintf(&cmd, |
| "LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH %s " |
| "--service_name=%s " |
| "--spec_dir_path=%s --callback_socket_name=%s", |
| ld_dir_path.c_str(), driver_binary_path.c_str(), |
| service_name.c_str(), driver_hal_spec_dir_path_.c_str(), |
| callback_socket_name.c_str()); |
| #endif |
| } |
| } else if (driver_type == VTS_DRIVER_TYPE_SHELL) { |
| if (bits == 32) { |
| driver_binary_path = driver_shell_binary32_; |
| } else { |
| driver_binary_path = driver_shell_binary64_; |
| } |
| size_t offset = driver_binary_path.find_last_of("/"); |
| string ld_dir_path = driver_binary_path.substr(0, offset); |
| |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| asprintf( |
| &cmd, |
| "LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH %s --server_socket_path=%s", |
| ld_dir_path.c_str(), driver_binary_path.c_str(), |
| socket_port_flie_path.c_str()); |
| #else // binder |
| LOG(ERROR) << "No binder implementation available."; |
| exit(-1); |
| #endif |
| } else { |
| LOG(ERROR) << "Unsupported driver type."; |
| } |
| |
| if (cmd) { |
| LOG(INFO) << "Launch a driver - " << cmd; |
| system(cmd); |
| LOG(INFO) << "driver exits"; |
| free(cmd); |
| } |
| exit(0); |
| } else if (pid > 0) { |
| for (int attempt = 0; attempt < 10; attempt++) { |
| sleep(1); |
| if (IsDriverRunning(service_name, 10)) { |
| result = SUCCESS; |
| break; |
| } |
| } |
| if (result) { |
| // TODO: use an attribute (client) of a newly defined class. |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = |
| android::vts::GetDriverSocketClient(service_name); |
| if (!client) { |
| #else // binder |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name); |
| if (!client.get()) { |
| #endif |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason("Failed to start a driver."); |
| // TODO: kill the driver? |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| if (driver_type == VTS_DRIVER_TYPE_HAL_CONVENTIONAL || |
| driver_type == VTS_DRIVER_TYPE_HAL_LEGACY || |
| driver_type == VTS_DRIVER_TYPE_HAL_HIDL) { |
| LOG(DEBUG) << "LoadHal " << module_name; |
| int32_t driver_id = client->LoadHal( |
| file_path, target_class, target_type, target_version_major, |
| target_version_minor, target_package, target_component_name, |
| hw_binder_service_name, module_name); |
| if (driver_id == -1) { |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason("Failed to load the selected HAL."); |
| } else { |
| response_msg.set_response_code(SUCCESS); |
| response_msg.set_result(to_string(driver_id)); |
| response_msg.set_reason("Loaded the selected HAL."); |
| LOG(DEBUG) << "set service_name " << service_name; |
| service_name_ = service_name; |
| } |
| } else if (driver_type == VTS_DRIVER_TYPE_SHELL) { |
| response_msg.set_response_code(SUCCESS); |
| response_msg.set_reason("Loaded the shell driver."); |
| LOG(DEBUG) << "set service_name " << service_name; |
| service_name_ = service_name; |
| } |
| |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| driver_client_ = client; |
| #endif |
| return VtsSocketSendMessage(response_msg); |
| } |
| } |
| response_msg.set_reason( |
| "Failed to fork a child process to start a driver."); |
| } |
| response_msg.set_response_code(FAIL); |
| LOG(ERROR) << "Can't fork a child process to run the vts_hal_driver."; |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::ReadSpecification( |
| const AndroidSystemControlCommandMessage& command_message) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name_); |
| if (!client.get()) { |
| #endif |
| return false; |
| } |
| |
| const string& result = client->ReadSpecification( |
| command_message.service_name(), command_message.target_class(), |
| command_message.target_type(), command_message.target_version_major(), |
| command_message.target_version_minor(), command_message.target_package()); |
| |
| return SendApiResult("ReadSpecification", result); |
| } |
| |
| bool AgentRequestHandler::ListApis() { |
| // TODO: use an attribute (client) of a newly defined class. |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name_); |
| if (!client.get()) { |
| #endif |
| return false; |
| } |
| return SendApiResult("GetAttribute", "", client->GetFunctions()); |
| } |
| |
| bool AgentRequestHandler::CallApi(const string& call_payload, |
| const string& uid) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| // TODO: use an attribute (client) of a newly defined class. |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name_); |
| if (!client.get()) { |
| #endif |
| return false; |
| } |
| |
| return SendApiResult("Call", client->Call(call_payload, uid)); |
| } |
| |
| bool AgentRequestHandler::GetAttribute(const string& payload) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| // TODO: use an attribute (client) of a newly defined class. |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name_); |
| if (!client.get()) { |
| #endif |
| return false; |
| } |
| |
| return SendApiResult("GetAttribute", client->GetAttribute(payload)); |
| } |
| |
| bool AgentRequestHandler::SendApiResult(const string& func_name, |
| const string& result, |
| const string& spec) { |
| AndroidSystemControlResponseMessage response_msg; |
| if (result.size() > 0 || spec.size() > 0) { |
| LOG(DEBUG) << "Call: success"; |
| response_msg.set_response_code(SUCCESS); |
| if (result.size() > 0) { |
| response_msg.set_result(result); |
| } |
| if (spec.size() > 0) { |
| response_msg.set_spec(spec); |
| } |
| } else { |
| LOG(ERROR) << "Call: fail"; |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason("Failed to call api function: " + func_name); |
| } |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::DefaultResponse() { |
| AndroidSystemControlResponseMessage response_msg; |
| response_msg.set_response_code(SUCCESS); |
| response_msg.set_reason("an example reason here"); |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::ExecuteShellCommand( |
| const AndroidSystemControlCommandMessage& command_message) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| LOG(ERROR) << " binder not supported."; |
| { |
| #endif |
| return false; |
| } |
| |
| auto result_message = |
| client->ExecuteShellCommand(command_message.shell_command()); |
| |
| AndroidSystemControlResponseMessage response_msg; |
| |
| if (result_message) { |
| CreateSystemControlResponseFromDriverControlResponse(*result_message, |
| &response_msg); |
| } else { |
| LOG(ERROR) << "ExecuteShellCommand: failed to call the api"; |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason("Failed to call the api."); |
| } |
| |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| void AgentRequestHandler::CreateSystemControlResponseFromDriverControlResponse( |
| const VtsDriverControlResponseMessage& driver_control_response_message, |
| AndroidSystemControlResponseMessage* system_control_response_message) { |
| |
| if (driver_control_response_message.response_code() == |
| VTS_DRIVER_RESPONSE_SUCCESS) { |
| LOG(DEBUG) << "ExecuteShellCommand: shell driver reported success"; |
| system_control_response_message->set_response_code(SUCCESS); |
| } else if (driver_control_response_message.response_code() == |
| VTS_DRIVER_RESPONSE_FAIL) { |
| LOG(ERROR) << "ExecuteShellCommand: shell driver reported fail"; |
| system_control_response_message->set_response_code(FAIL); |
| } else if (driver_control_response_message.response_code() == |
| UNKNOWN_VTS_DRIVER_RESPONSE_CODE) { |
| LOG(ERROR) << "ExecuteShellCommand: shell driver reported unknown"; |
| system_control_response_message->set_response_code(UNKNOWN_RESPONSE_CODE); |
| } |
| |
| for (const auto& log_stdout : driver_control_response_message.stdout()) { |
| system_control_response_message->add_stdout(log_stdout); |
| } |
| |
| for (const auto& log_stderr : driver_control_response_message.stderr()) { |
| system_control_response_message->add_stderr(log_stderr); |
| } |
| |
| for (const auto& exit_code : driver_control_response_message.exit_code()) { |
| system_control_response_message->add_exit_code(exit_code); |
| } |
| } |
| |
| bool AgentRequestHandler::ProcessFmqCommand( |
| const AndroidSystemControlCommandMessage& command_msg) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name_); |
| if (!client.get()) { |
| #endif |
| LOG(ERROR) << "Driver socket client is uninitialized."; |
| return false; |
| } |
| |
| AndroidSystemControlResponseMessage response_msg; |
| FmqResponseMessage* fmq_response = response_msg.mutable_fmq_response(); |
| FmqRequestMessage fmq_request = command_msg.fmq_request(); |
| // send the request message |
| bool success = client->ProcessFmqCommand(fmq_request, fmq_response); |
| |
| // prepare for response back to host |
| if (success) { |
| response_msg.set_response_code(SUCCESS); |
| } else { |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason("Failed to call api to process FMQ command."); |
| } |
| |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::ProcessHidlMemoryCommand( |
| const AndroidSystemControlCommandMessage& command_msg) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name_); |
| if (!client.get()) { |
| #endif |
| LOG(ERROR) << "Driver socket client is uninitialized."; |
| return false; |
| } |
| |
| AndroidSystemControlResponseMessage response_msg; |
| HidlMemoryResponseMessage* hidl_memory_response = |
| response_msg.mutable_hidl_memory_response(); |
| HidlMemoryRequestMessage hidl_memory_request = |
| command_msg.hidl_memory_request(); |
| // send the request message |
| bool success = client->ProcessHidlMemoryCommand(hidl_memory_request, |
| hidl_memory_response); |
| |
| // prepare for response back to host |
| if (success) { |
| response_msg.set_response_code(SUCCESS); |
| } else { |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason( |
| "Failed to call api to process hidl_memory command."); |
| } |
| |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::ProcessHidlHandleCommand( |
| const AndroidSystemControlCommandMessage& command_msg) { |
| #ifndef VTS_AGENT_DRIVER_COMM_BINDER // socket |
| VtsDriverSocketClient* client = driver_client_; |
| if (!client) { |
| #else // binder |
| android::sp<android::vts::IVtsFuzzer> client = |
| android::vts::GetBinderClient(service_name_); |
| if (!client.get()) { |
| #endif |
| LOG(ERROR) << "Driver socket client is uninitialized."; |
| return false; |
| } |
| |
| AndroidSystemControlResponseMessage response_msg; |
| HidlHandleResponseMessage* hidl_handle_response = |
| response_msg.mutable_hidl_handle_response(); |
| HidlHandleRequestMessage hidl_handle_request = |
| command_msg.hidl_handle_request(); |
| // send the request message |
| bool success = client->ProcessHidlHandleCommand(hidl_handle_request, |
| hidl_handle_response); |
| |
| // prepare for response back to host |
| if (success) { |
| response_msg.set_response_code(SUCCESS); |
| } else { |
| response_msg.set_response_code(FAIL); |
| response_msg.set_reason( |
| "Failed to call api to process hidl_handle command."); |
| } |
| |
| return VtsSocketSendMessage(response_msg); |
| } |
| |
| bool AgentRequestHandler::ProcessOneCommand() { |
| AndroidSystemControlCommandMessage command_msg; |
| if (!VtsSocketRecvMessage(&command_msg)) return false; |
| |
| LOG(DEBUG) << "command_type = " << command_msg.command_type(); |
| switch (command_msg.command_type()) { |
| case LIST_HALS: |
| return ListHals(command_msg.paths()); |
| case SET_HOST_INFO: |
| return SetHostInfo(command_msg.callback_port()); |
| case CHECK_DRIVER_SERVICE: |
| return CheckDriverService(command_msg.service_name(), NULL); |
| case LAUNCH_DRIVER_SERVICE: |
| return LaunchDriverService(command_msg); |
| case VTS_AGENT_COMMAND_READ_SPECIFICATION: |
| return ReadSpecification(command_msg); |
| case LIST_APIS: |
| return ListApis(); |
| case CALL_API: |
| return CallApi(command_msg.arg(), command_msg.driver_caller_uid()); |
| case VTS_AGENT_COMMAND_GET_ATTRIBUTE: |
| return GetAttribute(command_msg.arg()); |
| // for shell driver |
| case VTS_AGENT_COMMAND_EXECUTE_SHELL_COMMAND: |
| ExecuteShellCommand(command_msg); |
| return true; |
| case VTS_FMQ_COMMAND: |
| return ProcessFmqCommand(command_msg); |
| case VTS_HIDL_MEMORY_COMMAND: |
| return ProcessHidlMemoryCommand(command_msg); |
| case VTS_HIDL_HANDLE_COMMAND: |
| return ProcessHidlHandleCommand(command_msg); |
| default: |
| LOG(ERROR) << " ERROR unknown command " << command_msg.command_type(); |
| return DefaultResponse(); |
| } |
| } |
| |
| } // namespace vts |
| } // namespace android |