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 lib.handle = nullptr;
23 }
24
~ExtClient()25 ExtClient::~ExtClient()
26 {
27 if (lib.handle != nullptr) {
28 uv_dlclose(&lib);
29 }
30 }
31
GetPath()32 string 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
Init()46 bool 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
SharedLibraryExist()58 bool ExtClient::SharedLibraryExist()
59 {
60 string path = GetPath();
61 return Base::CheckDirectoryOrPath(path.c_str(), true, true);
62 }
63
ExecuteCommand(const string & command)64 void 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
Version(const std::string & str)113 void ExtClient::Version(const std::string &str)
114 {
115 const char *name = "HdcExtVersion";
116 Handle(str, name);
117 }
118
Help(const std::string & str)119 void ExtClient::Help(const std::string &str)
120 {
121 return;
122 }
123
Discover(const std::string & str)124 void ExtClient::Discover(const std::string &str)
125 {
126 const char *name = "HdcExtDiscover";
127 Handle(str, name);
128 }
129
Start(const std::string & str)130 void ExtClient::Start(const std::string &str)
131 {
132 const char *name = "HdcExtStart";
133 Handle(str, name);
134 }
135
Kill(const std::string & str)136 void ExtClient::Kill(const std::string &str)
137 {
138 const char *name = "HdcExtKill";
139 Handle(str, name);
140 }
141
Connect(const std::string & str)142 void 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
ListTargets(const std::string & str)151 void 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
UpdateList(const string & str)186 void 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
Shell(const std::string & str)202 void ExtClient::Shell(const std::string &str)
203 {
204 const char *name = "HdcExtShell";
205 string value = WithConnectKey(str);
206 Handle(value, name);
207 }
208
File(const std::string & str)209 void 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
Install(const std::string & str)217 void 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
Uninstall(const std::string & str)225 void ExtClient::Uninstall(const std::string &str)
226 {
227 const char *name = "HdcExtUninstall";
228 string value = WithConnectKey(str);
229 Handle(value, name);
230 }
231
Fport(const std::string & str)232 void ExtClient::Fport(const std::string &str)
233 {
234 const char *name = "HdcExtFport";
235 string value = WithConnectKey(str);
236 Handle(value, name);
237 }
238
Rport(const std::string & str)239 void ExtClient::Rport(const std::string &str)
240 {
241 const char *name = "HdcExtRport";
242 string value = WithConnectKey(str);
243 Handle(value, name);
244 }
245
Jpid(const std::string & str)246 void ExtClient::Jpid(const std::string &str)
247 {
248 const char *name = "HdcExtJpid";
249 string value = WithConnectKey(str);
250 Handle(value, name);
251 }
252
TrackJpid(const std::string & str)253 void ExtClient::TrackJpid(const std::string &str)
254 {
255 const char *name = "HdcExtTrackJpid";
256 string value = WithConnectKey(str);
257 Handle(value, name);
258 }
259
Utility(const std::string & str)260 void ExtClient::Utility(const std::string &str)
261 {
262 const char *name = "HdcExtUtility";
263 string value = WithConnectKey(str);
264 Handle(value, name);
265 }
266
Bugreport(const std::string & str)267 void ExtClient::Bugreport(const std::string &str)
268 {
269 const char *name = "HdcExtBugreport";
270 string value = WithConnectKey(str);
271 Handle(value, name);
272 }
273
WaitFor(const std::string & str)274 void ExtClient::WaitFor(const std::string &str)
275 {
276 std::thread([str]() {
277 WaitForExtent(str);
278 _exit(0);
279 }).detach();
280 }
281
UnknowCommand(const std::string & str)282 void ExtClient::UnknowCommand(const std::string &str)
283 {
284 const char *name = "HdcExtUnknowCommand";
285 Handle(str, name);
286 }
287
RemoveRemoteCwd(const std::string & str)288 std::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
HandleLib(const std::string & str,const char * name,uv_lib_t & lib)309 std::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
Handle(const std::string & str,const char * name)334 std::string ExtClient::Handle(const std::string &str, const char *name)
335 {
336 return HandleLib(str, name, this->lib);
337 }
338
WithConnectKey(const string & str)339 std::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
WaitForExtent(const std::string & str)352 void 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
OnExit(uv_process_t * req,int64_t exitStatus,int termSignal)367 static void OnExit(uv_process_t *req, int64_t exitStatus, int termSignal)
368 {
369 uv_close((uv_handle_t*) req, nullptr);
370 }
371
ExternalExecFunc(int argc,char * argv[])372 static 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
RegistExecFunc(uv_lib_t * lib)425 void 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