blob: 414d9d7184b78acc413d47eb81cebde8a6c5495f [file] [log] [blame]
/*
* 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.
*/
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <utils/RefBase.h>
#include <iostream>
#include <sstream>
#include "test/vts/agents/hal/proto/AndroidSystemControlMessage.pb.h"
#include "test/vts/sysfuzzer/common/proto/InterfaceSpecificationMessage.pb.h"
#include "BinderClient.h"
using namespace std;
#define MAX_FUZZER_ARGV_COUNT 30
#define TARGET_COMPONENT_DIR_PATH "/system/lib64/hw/"
namespace android {
namespace vts {
const static int kTcpPort = 5001;
AndroidSystemControlResponseMessage* RespondCheckFuzzerBinderService() {
AndroidSystemControlResponseMessage* response_msg =
new AndroidSystemControlResponseMessage();
sp<IVtsFuzzer> binder = GetBinderClient();
if (binder.get()) {
response_msg->set_response_code(SUCCESS);
response_msg->set_reason("an example success reason here");
} else {
response_msg->set_response_code(FAIL);
response_msg->set_reason("an example failure reason here");
}
return response_msg;
}
AndroidSystemControlResponseMessage* RespondStartFuzzerBinderService(
const string& args) {
cout << "starting fuzzer" << endl;
pid_t pid = fork();
ResponseCode result = FAIL;
if (pid == 0) { // child
cout << "Exec /system/bin/fuzzer " << args << endl;
char* cmd;
asprintf(&cmd, "/system/bin/fuzzer %s", args.c_str());
system(cmd);
cout << "fuzzer done" << endl;
free(cmd);
exit(0);
} else if (pid > 0){
for (int attempt = 0; attempt < 10; attempt++) {
sleep(1);
AndroidSystemControlResponseMessage* resp = RespondCheckFuzzerBinderService();
if (resp->response_code() == SUCCESS) {
result = SUCCESS;
break;
}
}
} else {
cerr << "can't fork a child process to run the fuzzer." << endl;
return NULL;
}
AndroidSystemControlResponseMessage* response_msg =
new AndroidSystemControlResponseMessage();
response_msg->set_response_code(result);
response_msg->set_reason("an example success reason here");
return response_msg;
}
AndroidSystemControlResponseMessage* RespondGetHals(const string& base_path) {
AndroidSystemControlResponseMessage* response_msg =
new AndroidSystemControlResponseMessage();
ResponseCode result = FAIL;
string files = "";
DIR *dp;
if (!(dp = opendir(base_path.c_str()))) {
cerr << "Error(" << errno << ") opening " << TARGET_COMPONENT_DIR_PATH << endl;
return NULL;
}
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")) {
files += string(dirp->d_name) + " ";
result = SUCCESS;
}
}
closedir(dp);
response_msg->set_reason(files);
return response_msg;
}
AndroidSystemControlResponseMessage* RespondSelectHal(
const string& file_name, int target_class, int target_type,
float target_version) {
// TODO: use an attribute (client) of a newly defined class.
android::sp<android::vts::IVtsFuzzer> client = android::vts::GetBinderClient();
if (!client.get()) return NULL;
int32_t result = client->LoadHal(file_name, target_class, target_type,
target_version);
cout << "LoadHal: " << result << endl;
AndroidSystemControlResponseMessage* response_msg =
new AndroidSystemControlResponseMessage();
if (result == 0) {
response_msg->set_response_code(SUCCESS);
response_msg->set_reason("Loaded the selected HAL.");
} else {
response_msg->set_response_code(FAIL);
response_msg->set_reason("Failed to load the selected HAL.");
}
return response_msg;
}
AndroidSystemControlResponseMessage* RespondGetFunctions() {
// TODO: use an attribute (client) of a newly defined class.
android::sp<android::vts::IVtsFuzzer> client = android::vts::GetBinderClient();
if (!client.get()) return NULL;
const char* result = client->GetFunctions();
cout << "GetFunctions: len " << strlen(result) << endl;
if (result) cout << "GetFunctions: " << result << endl;
AndroidSystemControlResponseMessage* response_msg =
new AndroidSystemControlResponseMessage();
if (result != NULL && strlen(result) > 0) {
response_msg->set_response_code(SUCCESS);
response_msg->set_reason(result);
} else {
response_msg->set_response_code(FAIL);
response_msg->set_reason("Failed to load the selected HAL.");
}
return response_msg;
}
AndroidSystemControlResponseMessage* RespondCallFunction(const string& call_payload) {
// TODO: use an attribute (client) of a newly defined class.
android::sp<android::vts::IVtsFuzzer> client = android::vts::GetBinderClient();
if (!client.get()) return NULL;
const char* result = client->Call(call_payload);
if (result) cout << "Call: " << result << endl;
AndroidSystemControlResponseMessage* response_msg =
new AndroidSystemControlResponseMessage();
if (result != NULL && strlen(result) > 0) {
response_msg->set_response_code(SUCCESS);
response_msg->set_reason(result);
} else {
response_msg->set_response_code(FAIL);
response_msg->set_reason("Failed to load the selected HAL.");
}
return response_msg;
}
AndroidSystemControlResponseMessage* RespondDefault() {
AndroidSystemControlResponseMessage* response_msg =
new AndroidSystemControlResponseMessage();
response_msg->set_response_code(SUCCESS);
response_msg->set_reason("an example reason here");
return response_msg;
}
// handles a new session.
int HandleSession(int fd) {
// If connection is established then start communicating
char buffer[4096];
char ch;
int index = 0;
int ret;
int n;
if (fd < 0) {
cerr << "invalid fd " << fd << endl;
return -1;
}
bzero(buffer, 4096);
while (true) {
if ((ret = read(fd, &ch, 1)) != 1) {
cerr << "can't read any data. code = " << ret << endl;
break;
}
if (index == 4096) {
cerr << "message too long (longer than " << index << " bytes)" << endl;
return -1;
}
if (ch == '\n') {
buffer[index] = '\0';
int len = atoi(buffer);
cout << "trying to read " << len << " bytes" << endl;
if (read(fd, buffer, len) != len) {
cerr << "can't read all data" << endl;
// TODO: handle by retrying
return -1;
}
buffer[len] = '\0';
AndroidSystemControlCommandMessage command_msg;
for (int i = 0; i < len; i++) {
cout << int(buffer[i]) << " ";
}
cout << endl;
if (!command_msg.ParseFromString(string(buffer))) {
cerr << "can't parse the cmd" << endl;
return -1;
}
cout << "type " << command_msg.command_type() << endl;
cout << "target_name " << command_msg.target_name() << endl;
AndroidSystemControlResponseMessage* response_msg = NULL;
switch (command_msg.command_type()) {
case CHECK_FUZZER_BINDER_SERVICE:
response_msg = RespondCheckFuzzerBinderService();
break;
case START_FUZZER_BINDER_SERVICE:
response_msg = RespondStartFuzzerBinderService(
command_msg.target_name());
break;
case GET_HALS:
if (command_msg.target_name().length() > 0) {
response_msg = RespondGetHals(command_msg.target_name());
} else {
response_msg = RespondGetHals(TARGET_COMPONENT_DIR_PATH);
}
break;
case SELECT_HAL:
response_msg = RespondSelectHal(command_msg.target_name(),
command_msg.target_class(),
command_msg.target_type(),
command_msg.target_version() / 100.0);
break;
case GET_FUNCTIONS:
response_msg = RespondGetFunctions();
break;
case CALL_FUNCTION:
response_msg = RespondCallFunction(command_msg.target_name());
break;
default:
response_msg = RespondDefault();
break;
}
if (!response_msg) {
cerr << "response_msg == NULL" << endl;
return -1;
}
string response_msg_str;
if (!response_msg->SerializeToString(&response_msg_str)) {
cerr << "can't serialize the response message to a string." << endl;
return -1;
}
// Write a response to the client
std::stringstream response_header;
response_header << response_msg_str.length() << "\n";
cout << "sending '" << response_header.str() << "'" << endl;
n = write(fd, response_header.str().c_str(),
response_header.str().length());
if (n < 0) {
cerr << "ERROR writing to socket" << endl;
return -1;
}
n = write(fd, response_msg_str.c_str(), response_msg_str.length());
cout << "sending '" << response_msg_str << "'" << endl;
if (n < 0) {
cerr << "ERROR writing to socket" << endl;
return -1;
}
delete response_msg;
index = 0;
} else {
buffer[index++] = ch;
}
}
return 0;
}
// Starts to run a TCP server (foreground).
int StartTcpServer() {
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
cerr << "Can't open the socket." << endl;
return -1;
}
// Initialize socket structure
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(kTcpPort);
// Now bind the host address using bind() call.
if (::bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) {
cerr << "Binding failed." << endl;
return -1;
}
while (true) {
// Now start listening for the clients, here process will go in sleep mode
// and will wait for the incoming connection
listen(sockfd, 5);
clilen = sizeof(cli_addr);
// Accept actual connection from the client
newsockfd = ::accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);
if (newsockfd < 0) {
cerr << "Accept failed" << endl;
return -1;
}
cout << "New session" << endl;
pid_t pid = fork();
if (pid == 0) { // child
exit(HandleSession(newsockfd));
} else if (pid < 0){
cerr << "can't fork a child process to handle a session." << endl;
return -1;
}
}
return 0;
}
} // namespace vts
} // namespace android