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