xref: /developtools/hdc/src/host/ext_client.cpp (revision cc290419)
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 **) &registExec);
431    if (rc == 0) {
432        registExec(reinterpret_cast<int *>(ExternalExecFunc));
433    }
434}
435}
436
437