1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "ext_client.h" 16#include "libgen.h" 17#include "common.h" 18 19namespace Hdc { 20ExtClient::ExtClient() 21{ 22 lib.handle = nullptr; 23} 24 25ExtClient::~ExtClient() 26{ 27 if (lib.handle != nullptr) { 28 uv_dlclose(&lib); 29 } 30} 31 32string ExtClient::GetPath() 33{ 34#ifdef _WIN32 35 string path = "libexternal_hdc.dll"; 36#elif defined(HOST_MAC) 37 string path = "libexternal_hdc.dylib"; 38#else 39 string path = "libexternal_hdc.z.so"; 40#endif 41 string hdcPath = Base::GetHdcAbsolutePath(); 42 int index = hdcPath.find_last_of(Base::GetPathSep()); 43 return (hdcPath.substr(0, index) + Base::GetPathSep() + path); 44} 45 46bool ExtClient::Init() 47{ 48 string path = GetPath(); 49 int rc = uv_dlopen(path.c_str(), &lib); 50 if (rc != 0) { 51 WRITE_LOG(LOG_FATAL, "uv_dlopen failed %s %s", path.c_str(), uv_dlerror(&lib)); 52 return false; 53 } 54 RegistExecFunc(&lib); 55 return true; 56} 57 58bool ExtClient::SharedLibraryExist() 59{ 60 string path = GetPath(); 61 return Base::CheckDirectoryOrPath(path.c_str(), true, true); 62} 63 64void ExtClient::ExecuteCommand(const string &command) 65{ 66 if (!strncmp(command.c_str(), CMDSTR_SOFTWARE_VERSION.c_str(), CMDSTR_SOFTWARE_VERSION.size())) { 67 Version(command); 68 } else if (!strncmp(command.c_str(), CMDSTR_SOFTWARE_HELP.c_str(), CMDSTR_SOFTWARE_HELP.size())) { 69 Help(command); 70 } else if (!strncmp(command.c_str(), CMDSTR_TARGET_DISCOVER.c_str(), CMDSTR_TARGET_DISCOVER.size())) { 71 Discover(command); 72 } else if (!strncmp(command.c_str(), CMDSTR_SERVICE_START.c_str(), CMDSTR_SERVICE_START.size())) { 73 Start(command); 74 } else if (!strncmp(command.c_str(), CMDSTR_SERVICE_KILL.c_str(), CMDSTR_SERVICE_KILL.size())) { 75 Kill(command); 76 } else if (!strncmp(command.c_str(), CMDSTR_CONNECT_TARGET.c_str(), CMDSTR_CONNECT_TARGET.size())) { 77 Connect(command); 78 } else if (!strncmp(command.c_str(), CMDSTR_LIST_TARGETS.c_str(), CMDSTR_LIST_TARGETS.size())) { 79 ListTargets(command); 80 } else if (!strncmp(command.c_str(), CMDSTR_SHELL.c_str(), CMDSTR_SHELL.size())) { 81 Shell(command); 82 } else if (!strncmp(command.c_str(), CMDSTR_FILE_SEND.c_str(), CMDSTR_FILE_SEND.size()) || 83 !strncmp(command.c_str(), CMDSTR_FILE_RECV.c_str(), CMDSTR_FILE_RECV.size())) { 84 File(command); 85 } else if (!strncmp(command.c_str(), CMDSTR_APP_INSTALL.c_str(), CMDSTR_APP_INSTALL.size())) { 86 Install(command); 87 } else if (!strncmp(command.c_str(), CMDSTR_APP_UNINSTALL.c_str(), CMDSTR_APP_UNINSTALL.size())) { 88 Uninstall(command); 89 } else if (!strncmp(command.c_str(), CMDSTR_FORWARD_FPORT.c_str(), CMDSTR_FORWARD_FPORT.size())) { 90 Fport(command); 91 } else if (!strncmp(command.c_str(), CMDSTR_FORWARD_RPORT.c_str(), CMDSTR_FORWARD_RPORT.size())) { 92 Rport(command); 93 } else if (!strncmp(command.c_str(), CMDSTR_LIST_JDWP.c_str(), CMDSTR_LIST_JDWP.size())) { 94 Jpid(command); 95 } else if (!strncmp(command.c_str(), CMDSTR_TRACK_JDWP.c_str(), CMDSTR_TRACK_JDWP.size())) { 96 TrackJpid(command); 97 } else if (!strncmp(command.c_str(), (CMDSTR_SHELL + " ").c_str(), CMDSTR_SHELL.size() + 1) || 98 !strncmp(command.c_str(), CMDSTR_TARGET_REBOOT.c_str(), CMDSTR_TARGET_REBOOT.size()) || 99 !strncmp(command.c_str(), CMDSTR_TARGET_MOUNT.c_str(), CMDSTR_TARGET_MOUNT.size()) || 100 !strncmp(command.c_str(), CMDSTR_STARTUP_MODE.c_str(), CMDSTR_STARTUP_MODE.size()) || 101 !strncmp(command.c_str(), CMDSTR_TARGET_MODE.c_str(), CMDSTR_TARGET_MODE.size()) || 102 !strncmp(command.c_str(), CMDSTR_HILOG.c_str(), CMDSTR_HILOG.size())) { 103 Utility(command); 104 } else if (!strncmp(command.c_str(), CMDSTR_BUGREPORT.c_str(), CMDSTR_BUGREPORT.size())) { 105 Bugreport(command); 106 } else if (!strncmp(command.c_str(), CMDSTR_WAIT_FOR.c_str(), CMDSTR_WAIT_FOR.size())) { 107 WaitFor(command); 108 } else { 109 UnknowCommand(command); 110 } 111} 112 113void ExtClient::Version(const std::string &str) 114{ 115 const char *name = "HdcExtVersion"; 116 Handle(str, name); 117} 118 119void ExtClient::Help(const std::string &str) 120{ 121 return; 122} 123 124void ExtClient::Discover(const std::string &str) 125{ 126 const char *name = "HdcExtDiscover"; 127 Handle(str, name); 128} 129 130void ExtClient::Start(const std::string &str) 131{ 132 const char *name = "HdcExtStart"; 133 Handle(str, name); 134} 135 136void ExtClient::Kill(const std::string &str) 137{ 138 const char *name = "HdcExtKill"; 139 Handle(str, name); 140} 141 142void ExtClient::Connect(const std::string &str) 143{ 144 const char *name = "HdcExtConnect"; 145 string res = Handle(str, name); 146 if (res.find("connected to") != std::string::npos) { 147 _exit(0); 148 } 149} 150 151void ExtClient::ListTargets(const std::string &str) 152{ 153 typedef void (*HdcExtListTargets)(const char *, uint64_t, char *, uint64_t &); 154 const char *name = "HdcExtListTargets"; 155 HdcExtListTargets listTargets; 156 int rc = uv_dlsym(&lib, name, (void **) &listTargets); 157 if (rc != 0) { 158 WRITE_LOG(LOG_FATAL, "uv_dlsym %s failed %s", name, uv_dlerror(&lib)); 159 } else { 160 uint64_t size = 4096; 161 char *buffer = new(std::nothrow) char[size](); 162 if (buffer == nullptr) { 163 WRITE_LOG(LOG_FATAL, "new buffer failed with function %s", name); 164 return; 165 } 166 listTargets(str.c_str(), str.size(), buffer, size); 167 string extdevs(buffer); 168 UpdateList(extdevs); 169 delete[] buffer; 170 if (extdevs.empty()) { 171 return; 172 } 173 if (g_show) { 174 const string listv = "list targets -v"; 175 if (!strncmp(str.c_str(), listv.c_str(), listv.size())) { 176 string all = extdevs; 177 all = Base::ReplaceAll(all, "\n", "\texternal\n"); 178 Base::PrintMessage("%s", all.c_str()); 179 } else { 180 Base::PrintMessage("%s", extdevs.c_str()); 181 } 182 } 183 } 184} 185 186void ExtClient::UpdateList(const string &str) 187{ 188 if (str.empty()) { 189 return; 190 } 191 vector<string> devs; 192 Base::SplitString(str, "\n", devs); 193 for (size_t i = 0; i < devs.size(); i++) { 194 string::size_type pos = devs[i].find("\t"); 195 if (pos != string::npos || (pos = devs[i].find(" ")) != string::npos) { 196 string key = devs[i].substr(0, pos); 197 g_lists[key] = "external"; 198 } 199 } 200} 201 202void ExtClient::Shell(const std::string &str) 203{ 204 const char *name = "HdcExtShell"; 205 string value = WithConnectKey(str); 206 Handle(value, name); 207} 208 209void ExtClient::File(const std::string &str) 210{ 211 const char *name = "HdcExtFile"; 212 std::string cmd = RemoveRemoteCwd(str); 213 string value = WithConnectKey(cmd); 214 Handle(value, name); 215} 216 217void ExtClient::Install(const std::string &str) 218{ 219 const char *name = "HdcExtInstall"; 220 std::string cmd = RemoveRemoteCwd(str); 221 string value = WithConnectKey(cmd); 222 Handle(value, name); 223} 224 225void ExtClient::Uninstall(const std::string &str) 226{ 227 const char *name = "HdcExtUninstall"; 228 string value = WithConnectKey(str); 229 Handle(value, name); 230} 231 232void ExtClient::Fport(const std::string &str) 233{ 234 const char *name = "HdcExtFport"; 235 string value = WithConnectKey(str); 236 Handle(value, name); 237} 238 239void ExtClient::Rport(const std::string &str) 240{ 241 const char *name = "HdcExtRport"; 242 string value = WithConnectKey(str); 243 Handle(value, name); 244} 245 246void ExtClient::Jpid(const std::string &str) 247{ 248 const char *name = "HdcExtJpid"; 249 string value = WithConnectKey(str); 250 Handle(value, name); 251} 252 253void ExtClient::TrackJpid(const std::string &str) 254{ 255 const char *name = "HdcExtTrackJpid"; 256 string value = WithConnectKey(str); 257 Handle(value, name); 258} 259 260void ExtClient::Utility(const std::string &str) 261{ 262 const char *name = "HdcExtUtility"; 263 string value = WithConnectKey(str); 264 Handle(value, name); 265} 266 267void ExtClient::Bugreport(const std::string &str) 268{ 269 const char *name = "HdcExtBugreport"; 270 string value = WithConnectKey(str); 271 Handle(value, name); 272} 273 274void ExtClient::WaitFor(const std::string &str) 275{ 276 std::thread([str]() { 277 WaitForExtent(str); 278 _exit(0); 279 }).detach(); 280} 281 282void ExtClient::UnknowCommand(const std::string &str) 283{ 284 const char *name = "HdcExtUnknowCommand"; 285 Handle(str, name); 286} 287 288std::string ExtClient::RemoveRemoteCwd(const std::string &str) 289{ 290 int argc = 0; 291 std::string cmd = str; 292 char **argv = Base::SplitCommandToArgs(cmd.c_str(), &argc); 293 if (argv == nullptr) { 294 return cmd; 295 } 296 for (int i = 0; i < argc; i++) { 297 if (argv[i] == CMDSTR_REMOTE_PARAMETER) { 298 std::string remove = Base::StringFormat("%s %s \"%s\" ", argv[i], argv[i + 1], argv[i + 2]); 299 if (cmd.find(remove) != std::string::npos) { 300 cmd.replace(cmd.find(remove), remove.size(), ""); 301 } 302 break; 303 } 304 } 305 delete[](reinterpret_cast<char *>(argv)); 306 return cmd; 307} 308 309std::string ExtClient::HandleLib(const std::string &str, const char *name, uv_lib_t &lib) 310{ 311 typedef void (*HdcExtCommand)(const char *, uint64_t, char *, uint64_t &); 312 HdcExtCommand command; 313 std::string strBuf; 314 int rc = uv_dlsym(&lib, name, (void **) &command); 315 if (rc != 0) { 316 WRITE_LOG(LOG_FATAL, "uv_dlsym %s failed %s", name, uv_dlerror(&lib)); 317 } else { 318 uint64_t size = 4096; 319 char *buffer = new(std::nothrow) char[size](); 320 if (buffer == nullptr) { 321 WRITE_LOG(LOG_FATAL, "new buffer failed with function %s", name); 322 return ""; 323 } 324 command(str.c_str(), str.size(), buffer, size); 325 strBuf = buffer; 326 if (!strBuf.empty()) { 327 Base::PrintMessage("%s", strBuf.c_str()); 328 } 329 delete[] buffer; 330 } 331 return strBuf; 332} 333 334std::string ExtClient::Handle(const std::string &str, const char *name) 335{ 336 return HandleLib(str, name, this->lib); 337} 338 339std::string ExtClient::WithConnectKey(const string &str) 340{ 341 std::string value; 342 if (!connectKey.empty()) { 343 value = "-t " + connectKey + " "; 344 } 345 if (!containerInOut.empty()) { 346 value = value + containerInOut + " "; 347 } 348 value = value + str; 349 return value; 350} 351 352void ExtClient::WaitForExtent(const std::string &str) 353{ 354 uv_lib_t uvLib; 355 string path = GetPath(); 356 int rc = uv_dlopen(path.c_str(), &uvLib); 357 if (rc != 0) { 358 WRITE_LOG(LOG_FATAL, "uv_dlopen failed %s %s", path.c_str(), uv_dlerror(&uvLib)); 359 return; 360 } 361 RegistExecFunc(&uvLib); 362 const char *name = "HdcExtWaitFor"; 363 HandleLib(str, name, uvLib); 364 uv_dlclose(&uvLib); 365} 366 367static void OnExit(uv_process_t *req, int64_t exitStatus, int termSignal) 368{ 369 uv_close((uv_handle_t*) req, nullptr); 370} 371 372static int ExternalExecFunc(int argc, char *argv[]) 373{ 374#define EXTERNAL_KEEP_FDS 3 375 uv_loop_t loop; 376 uv_process_t childReq = { 0 }; 377 uv_process_options_t options = { 0 }; 378 uv_stdio_container_t childStdio[EXTERNAL_KEEP_FDS]; 379 380 if (argc <= 0) { 381 return 1; 382 } 383 384 uv_loop_init(&loop); 385 386 for (int i = 0; i < EXTERNAL_KEEP_FDS; i++) { 387 childStdio[i].flags = UV_INHERIT_FD; 388 childStdio[i].data.fd = i; 389 } 390 391 size_t pathSize = BUF_SIZE_DEFAULT4; 392 char execPath[pathSize]; 393 (void)memset_s(execPath, pathSize, 0, pathSize); 394 int ret = uv_exepath(execPath, &pathSize); 395 if (ret < 0) { 396 return 1; 397 } 398 string path = string(dirname(execPath)) + "/" + string(argv[0]); 399 options.file = path.c_str(); 400 options.args = argv; 401 options.exit_cb = OnExit; 402 options.stdio_count = EXTERNAL_KEEP_FDS; 403 options.stdio = childStdio; 404 405 if (uv_spawn(&loop, &childReq, &options) != 0) { 406 return 1; 407 } 408 uv_run(&loop, UV_RUN_DEFAULT); 409 410#ifdef HOST_MINGW 411 DWORD status = 0; 412 if (GetExitCodeProcess(childReq.process_handle, &status)) { 413 return uv_translate_sys_error(GetLastError()); 414 } 415#else 416 int status = 0; 417 if (!WIFEXITED(childReq.status)) { 418 return errno; 419 } 420 status = WEXITSTATUS(childReq.status); 421#endif 422 return static_cast<int>(status); 423} 424 425void ExtClient::RegistExecFunc(uv_lib_t *lib) 426{ 427 typedef void (*HdcExtRegistExec)(int *); 428 HdcExtRegistExec registExec; 429 const char *name = "HdcExtRegistExecFunc"; 430 int rc = uv_dlsym(lib, name, (void **) ®istExec); 431 if (rc == 0) { 432 registExec(reinterpret_cast<int *>(ExternalExecFunc)); 433 } 434} 435} 436 437