blob: 5443ad9c36a500b95cfa6ecf4ec5aa27ecb84e3f [file] [log] [blame]
/*
* Copyright (C) 2022 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 <signal.h>
#include <stdio.h>
#include <sys/wait.h>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#ifndef HOST
#include "ApPowerControl.h"
#endif // #ifndef HOST
#include "TestWakeupClientServiceImpl.h"
#include <grpc/grpc.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
using ::android::hardware::automotive::remoteaccess::TestWakeupClientServiceImpl;
using ::grpc::Server;
using ::grpc::ServerBuilder;
using ::grpc::ServerWriter;
constexpr int SHUTDOWN_REQUEST = 289410889;
constexpr int VEHICLE_IN_USE = 287313738;
const char* COMMAND_RUN_EMU = "source ~/.aae-toolbox/bin/bashrc && aae emulator run";
const char* COMMAND_SET_VHAL_PROP =
"adb -s emulator-5554 wait-for-device && adb -s emulator-5554 root "
"&& sleep 1 && adb -s emulator-5554 wait-for-device && adb -s emulator-5554 shell "
"dumpsys android.hardware.automotive.vehicle.IVehicle/default --set %d -i %d";
pid_t emuPid = 0;
void RunServer(const std::string& serviceAddr,
std::shared_ptr<TestWakeupClientServiceImpl> service) {
ServerBuilder builder;
builder.AddListeningPort(serviceAddr, grpc::InsecureServerCredentials());
builder.RegisterService(service.get());
std::unique_ptr<Server> server(builder.BuildAndStart());
printf("Test Remote Access GRPC Server listening on %s\n", serviceAddr.c_str());
server->Wait();
}
pid_t runCommand(const char* bashCommand) {
pid_t pid = fork();
if (pid == 0) {
// In child process. Put it into a separate process group so we can kill it.
setpgid(0, 0);
execl("/bin/bash", "bash", "-c", bashCommand, /*terminateArg=*/nullptr);
exit(0);
} else {
return pid;
}
}
void updateEmuStatus() {
if (emuPid == 0) {
return;
}
pid_t pid = waitpid(emuPid, nullptr, WNOHANG);
if (pid == emuPid) {
// Emu process already exited. If Emu process is still running, pid will be 0.
emuPid = 0;
}
}
bool powerOnEmu() {
updateEmuStatus();
if (emuPid != 0) {
printf("The emulator is already running\n");
return false;
}
emuPid = runCommand(COMMAND_RUN_EMU);
printf("Emulator started in process: %d\n", emuPid);
return true;
}
bool powerOn() {
#ifdef HOST
return powerOnEmu();
#else
printf("power on is only supported on host\n");
return false;
#endif
}
const char* getSetPropCommand(int propId, int value) {
int size = snprintf(nullptr, 0, COMMAND_SET_VHAL_PROP, propId, value);
char* command = new char[size + 1];
snprintf(command, size + 1, COMMAND_SET_VHAL_PROP, propId, value);
return command;
}
const char* getSetPropCommand(int propId) {
return getSetPropCommand(propId, /*value=*/1);
}
void powerOffEmu() {
updateEmuStatus();
if (emuPid == 0) {
printf("The emulator is not running\n");
return;
}
const char* command = getSetPropCommand(SHUTDOWN_REQUEST);
runCommand(command);
delete[] command;
waitpid(emuPid, nullptr, /*options=*/0);
emuPid = 0;
}
void powerOff() {
#ifdef HOST
powerOffEmu();
#else
printf("power off is only supported on host\n");
#endif
}
void setVehicleInUse(bool vehicleInUse) {
#ifdef HOST
printf("Set vehicleInUse to %d\n", vehicleInUse);
int value = 0;
if (vehicleInUse) {
value = 1;
}
const char* command = getSetPropCommand(VEHICLE_IN_USE, value);
runCommand(command);
delete[] command;
#else
printf("set vehicleInUse is only supported on host\n");
#endif
}
void help() {
std::cout << "Remote Access Host Test Utility" << std::endl
<< "help:\t"
<< "Print out this help info" << std::endl
<< "genFakeTask start [clientID]:\t"
<< "Start generating a fake task every 5s" << std::endl
<< "genFakeTask stop:\t"
<< "Stop the fake task generation" << std::endl
<< "status:\t"
<< "Print current status" << std::endl
<< "power on:\t"
<< "Power on the emulator, simulate user enters vehicle while AP is off"
<< " (only supported on host)" << std::endl
<< "power off:\t"
<< "Power off the emulator, simulate user leaves vehicle"
<< " (only supported on host)" << std::endl
<< "inject task [clientID] [taskData]:\t"
<< "Inject a remote task" << std::endl
<< "set vehicleInUse:\t"
<< "Set vehicle in use, simulate user enter vehicle while boot up for remote task "
<< "(only supported on host)" << std::endl;
}
void parseCommand(const std::string& userInput,
std::shared_ptr<TestWakeupClientServiceImpl> service) {
if (userInput == "") {
// ignore empty line.
} else if (userInput == "help") {
help();
} else if (userInput.rfind("genFakeTask start", 0) == 0) {
std::string clientId;
std::stringstream ss;
ss << userInput;
int i = 0;
while (std::getline(ss, clientId, ' ')) {
i++;
if (i == 3) {
break;
}
}
if (i != 3) {
printf("Missing clientId, see 'help'\n");
return;
}
service->startGeneratingFakeTask(clientId);
} else if (userInput == "genFakeTask stop") {
service->stopGeneratingFakeTask();
} else if (userInput == "status") {
printf("isWakeupRequired: %B, isRemoteTaskConnectionAlive: %B\n",
service->isWakeupRequired(), service->isRemoteTaskConnectionAlive());
} else if (userInput == "power on") {
powerOn();
} else if (userInput == "power off") {
powerOff();
} else if (userInput.rfind("inject task", 0) == 0) {
std::stringstream ss;
ss << userInput;
std::string data;
std::string taskData;
std::string clientId;
int i = 0;
while (std::getline(ss, data, ' ')) {
i++;
if (i == 3) {
clientId = data;
}
if (i == 4) {
taskData = data;
}
}
if (taskData == "" || clientId == "") {
printf("Missing taskData or clientId, see 'help'\n");
return;
}
service->injectTask(taskData, clientId);
printf("Remote task with client ID: %s, data: %s injected\n", clientId.c_str(),
taskData.c_str());
} else if (userInput == "set vehicleInUse") {
setVehicleInUse(true);
} else {
printf("Unknown command, see 'help'\n");
}
}
void saHandler(int signum) {
if (emuPid != 0) {
kill(-emuPid, signum);
waitpid(emuPid, nullptr, /*options=*/0);
// Sleep for 1 seconds to allow emulator to print out logs.
sleep(1);
}
exit(-1);
}
class MyTestWakeupClientServiceImpl final : public TestWakeupClientServiceImpl {
public:
void wakeupApplicationProcessor() override {
#ifdef HOST
if (powerOnEmu()) {
// If we wake up AP to execute remote task, vehicle in use should be false.
setVehicleInUse(false);
}
#else
wakeupAp();
#endif
};
};
int main(int argc, char** argv) {
std::string serviceAddr = GRPC_SERVICE_ADDRESS;
if (argc > 1) {
serviceAddr = argv[1];
}
// Let the server thread run, we will force kill the server when we exit the program.
std::shared_ptr<TestWakeupClientServiceImpl> service =
std::make_shared<MyTestWakeupClientServiceImpl>();
std::thread serverThread([serviceAddr, service] { RunServer(serviceAddr, service); });
// Register the signal handler for SIGTERM and SIGINT so that we can stop the emulator before
// exit.
struct sigaction sa = {};
sigemptyset(&sa.sa_mask);
sa.sa_handler = saHandler;
sigaction(SIGTERM, &sa, nullptr);
sigaction(SIGINT, &sa, nullptr);
// Start processing the user inputs.
std::string userInput;
while (true) {
std::cout << ">>> ";
std::getline(std::cin, userInput);
parseCommand(userInput, service);
}
return 0;
}