1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <signal.h>
18 #include <stdio.h>
19 #include <sys/wait.h>
20 #include <iostream>
21 #include <sstream>
22 #include <string>
23 #include <thread>
24
25 #ifndef HOST
26 #include "ApPowerControl.h"
27 #endif // #ifndef HOST
28
29 #include "TestWakeupClientServiceImpl.h"
30
31 #include <grpc/grpc.h>
32 #include <grpcpp/security/server_credentials.h>
33 #include <grpcpp/server.h>
34 #include <grpcpp/server_builder.h>
35
36 namespace {
37
38 using ::android::hardware::automotive::remoteaccess::BOOTUP_REASON_SYSTEM_ENTER_GARAGE_MODE;
39 using ::android::hardware::automotive::remoteaccess::BOOTUP_REASON_SYSTEM_REMOTE_ACCESS;
40 using ::android::hardware::automotive::remoteaccess::BOOTUP_REASON_USER_POWER_ON;
41 using ::android::hardware::automotive::remoteaccess::PowerControllerServiceImpl;
42 using ::android::hardware::automotive::remoteaccess::ServiceImpl;
43 using ::android::hardware::automotive::remoteaccess::WakeupClientServiceImpl;
44 using ::grpc::Server;
45 using ::grpc::ServerBuilder;
46 using ::grpc::ServerWriter;
47
48 constexpr int SHUTDOWN_REQUEST = 289410889;
49 constexpr int VEHICLE_IN_USE = 287313738;
50 constexpr char COMMAND_RUN_EMU_LOCAL_IMAGE[] =
51 "source ~/.aae-toolbox/bin/bashrc && aae emulator run";
52 constexpr char COMMAND_RUN_EMU[] = "./launch_emu.sh -v \"-writable-system -selinux permissive\"";
53 constexpr char COMMAND_SET_VHAL_PROP[] =
54 "adb -s emulator-5554 wait-for-device && adb -s emulator-5554 root "
55 "&& sleep 1 && adb -s emulator-5554 wait-for-device && adb -s emulator-5554 shell "
56 "dumpsys android.hardware.automotive.vehicle.IVehicle/default --set %d -i %d";
57
58 pid_t emuPid = 0;
59 const char* runEmuCommand = COMMAND_RUN_EMU;
60
61 } // namespace
62
RunServer(const std::string & serviceAddr,std::shared_ptr<ServiceImpl> service)63 void RunServer(const std::string& serviceAddr, std::shared_ptr<ServiceImpl> service) {
64 ServerBuilder builder;
65 builder.AddListeningPort(serviceAddr, grpc::InsecureServerCredentials());
66 WakeupClientServiceImpl wakeupClientService(service.get());
67 builder.RegisterService(&wakeupClientService);
68 PowerControllerServiceImpl powerControllerService(service.get());
69 builder.RegisterService(&powerControllerService);
70 std::unique_ptr<Server> server(builder.BuildAndStart());
71 printf("Test Remote Access GRPC Server listening on %s\n", serviceAddr.c_str());
72 server->Wait();
73 }
74
runCommand(const char * bashCommand)75 pid_t runCommand(const char* bashCommand) {
76 pid_t pid = fork();
77 if (pid == 0) {
78 // In child process. Put it into a separate process group so we can kill it.
79 setpgid(0, 0);
80 execl("/bin/bash", "bash", "-c", bashCommand, /*terminateArg=*/nullptr);
81 exit(0);
82 } else {
83 return pid;
84 }
85 }
86
updateEmuStatus()87 void updateEmuStatus() {
88 if (emuPid == 0) {
89 return;
90 }
91 pid_t pid = waitpid(emuPid, nullptr, WNOHANG);
92 if (pid == emuPid) {
93 // Emu process already exited. If Emu process is still running, pid will be 0.
94 emuPid = 0;
95 }
96 }
97
powerOnEmu(ServiceImpl * service,int32_t bootupReason)98 bool powerOnEmu(ServiceImpl* service, int32_t bootupReason) {
99 updateEmuStatus();
100 if (emuPid != 0) {
101 printf("The emulator is already running\n");
102 return false;
103 }
104 service->setBootupReason(bootupReason);
105 emuPid = runCommand(runEmuCommand);
106 printf("Emulator started in process: %d\n", emuPid);
107 return true;
108 }
109
powerOn(ServiceImpl * service,int32_t bootupReason)110 bool powerOn(ServiceImpl* service, int32_t bootupReason) {
111 #ifdef HOST
112 return powerOnEmu(service, bootupReason);
113 #else
114 printf("power on is only supported on host\n");
115 return false;
116 #endif
117 }
118
getSetPropCommand(int propId,int value)119 const char* getSetPropCommand(int propId, int value) {
120 int size = snprintf(nullptr, 0, COMMAND_SET_VHAL_PROP, propId, value);
121 char* command = new char[size + 1];
122 snprintf(command, size + 1, COMMAND_SET_VHAL_PROP, propId, value);
123 return command;
124 }
125
getSetPropCommand(int propId)126 const char* getSetPropCommand(int propId) {
127 return getSetPropCommand(propId, /*value=*/1);
128 }
129
powerOffEmu()130 void powerOffEmu() {
131 updateEmuStatus();
132 if (emuPid == 0) {
133 printf("The emulator is not running\n");
134 return;
135 }
136 const char* command = getSetPropCommand(SHUTDOWN_REQUEST);
137 runCommand(command);
138 delete[] command;
139 waitpid(emuPid, nullptr, /*options=*/0);
140 emuPid = 0;
141 }
142
powerOff()143 void powerOff() {
144 #ifdef HOST
145 powerOffEmu();
146 #else
147 printf("power off is only supported on host\n");
148 #endif
149 }
150
help()151 void help() {
152 std::cout << "Remote Access Host Test Utility" << std::endl
153 << "help:\t"
154 << "Print out this help info" << std::endl
155 << "genFakeTask start [clientID]:\t"
156 << "Start generating a fake task every 5s" << std::endl
157 << "genFakeTask stop:\t"
158 << "Stop the fake task generation" << std::endl
159 << "status:\t"
160 << "Print current status" << std::endl
161 << "power on:\t"
162 << "Power on the emulator, simulate user enters vehicle while AP is off"
163 << " (only supported on host)" << std::endl
164 << "power off:\t"
165 << "Power off the emulator, simulate user leaves vehicle"
166 << " (only supported on host)" << std::endl
167 << "inject task [clientID] [taskData]:\t"
168 << "Inject a remote task" << std::endl
169 << "set vehicleInUse:\t"
170 << "Set vehicle in use, simulate user enter vehicle while boot up for remote task "
171 << "(only supported on host)" << std::endl;
172 }
173
parseCommand(const std::string & userInput,std::shared_ptr<ServiceImpl> service)174 void parseCommand(const std::string& userInput, std::shared_ptr<ServiceImpl> service) {
175 if (userInput == "") {
176 // ignore empty line.
177 } else if (userInput == "help") {
178 help();
179 } else if (userInput.rfind("genFakeTask start", 0) == 0) {
180 std::string clientId;
181 std::stringstream ss;
182 ss << userInput;
183 int i = 0;
184 while (std::getline(ss, clientId, ' ')) {
185 i++;
186 if (i == 3) {
187 break;
188 }
189 }
190 if (i != 3) {
191 printf("Missing clientId, see 'help'\n");
192 return;
193 }
194 service->startGeneratingFakeTask(clientId);
195 } else if (userInput == "genFakeTask stop") {
196 service->stopGeneratingFakeTask();
197 } else if (userInput == "status") {
198 printf("isWakeupRequired: %B, isRemoteTaskConnectionAlive: %B\n",
199 service->isWakeupRequired(), service->isRemoteTaskConnectionAlive());
200 } else if (userInput == "power on") {
201 service->setVehicleInUse(true);
202 powerOn(service.get(), BOOTUP_REASON_USER_POWER_ON);
203 } else if (userInput == "power off") {
204 service->setVehicleInUse(false);
205 powerOff();
206 } else if (userInput.rfind("inject task", 0) == 0) {
207 std::stringstream ss;
208 ss << userInput;
209 std::string data;
210 std::string taskData;
211 std::string clientId;
212 int i = 0;
213 while (std::getline(ss, data, ' ')) {
214 i++;
215 if (i == 3) {
216 clientId = data;
217 }
218 if (i == 4) {
219 taskData = data;
220 }
221 }
222 if (taskData == "" || clientId == "") {
223 printf("Missing taskData or clientId, see 'help'\n");
224 return;
225 }
226 service->injectTask(taskData, clientId);
227 printf("Remote task with client ID: %s, data: %s injected\n", clientId.c_str(),
228 taskData.c_str());
229 } else if (userInput == "set vehicleInUse") {
230 service->setVehicleInUse(true);
231 } else {
232 printf("Unknown command, see 'help'\n");
233 }
234 }
235
saHandler(int signum)236 void saHandler(int signum) {
237 if (emuPid != 0) {
238 kill(-emuPid, signum);
239 waitpid(emuPid, nullptr, /*options=*/0);
240 // Sleep for 1 seconds to allow emulator to print out logs.
241 sleep(1);
242 }
243 exit(-1);
244 }
245
246 class MyServiceImpl final : public ServiceImpl {
247 public:
wakeupApplicationProcessor(int32_t bootupReason)248 void wakeupApplicationProcessor(int32_t bootupReason) override {
249 #ifdef HOST
250 powerOnEmu(this, bootupReason);
251 #else
252 wakeupAp();
253 #endif
254 };
255 };
256
257 // Usage: TestWakeupClientServerHost [--local-image] [service_address_to_start]
main(int argc,char ** argv)258 int main(int argc, char** argv) {
259 std::string serviceAddr = GRPC_SERVICE_ADDRESS;
260 for (int i = 1; i < argc; i++) {
261 char* arg = argv[1];
262 if (strcmp(arg, "--local-image") == 0) {
263 runEmuCommand = COMMAND_RUN_EMU_LOCAL_IMAGE;
264 continue;
265 }
266 serviceAddr = arg;
267 }
268 // Let the server thread run, we will force kill the server when we exit the program.
269 std::shared_ptr<ServiceImpl> service = std::make_shared<MyServiceImpl>();
270 std::thread serverThread([serviceAddr, service] { RunServer(serviceAddr, service); });
271
272 // Register the signal handler for SIGTERM and SIGINT so that we can stop the emulator before
273 // exit.
274 struct sigaction sa = {};
275 sigemptyset(&sa.sa_mask);
276 sa.sa_handler = saHandler;
277 sigaction(SIGTERM, &sa, nullptr);
278 sigaction(SIGINT, &sa, nullptr);
279
280 // Start processing the user inputs.
281 std::string userInput;
282 while (true) {
283 std::cout << ">>> ";
284 std::getline(std::cin, userInput);
285 parseCommand(userInput, service);
286 }
287 return 0;
288 }
289