xref: /developtools/hdc/src/host/host_app.cpp (revision cc290419)
1/*
2 * Copyright (C) 2021 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 "host_app.h"
16#include "compress.h"
17
18namespace Hdc {
19HdcHostApp::HdcHostApp(HTaskInfo hTaskInfo)
20    : HdcTransferBase(hTaskInfo)
21{
22    commandBegin = CMD_APP_BEGIN;
23    commandData = CMD_APP_DATA;
24    originLocalDir = "";
25    isStableBuf = hTaskInfo->isStableBuf;
26}
27
28HdcHostApp::~HdcHostApp()
29{
30}
31
32string HdcHostApp::Dir2Tar(const char *dir)
33{
34    WRITE_LOG(LOG_DEBUG, "dir:%s", dir);
35    string tarpath;
36    uv_fs_t req;
37    int r = uv_fs_lstat(nullptr, &req, dir, nullptr);
38    uv_fs_req_cleanup(&req);
39    if (r == 0 && (req.statbuf.st_mode & S_IFDIR)) {  // is dir
40        string sdir = dir;
41        string tarname = Base::GetRandomString(EXPECTED_LEN) + ".tar";
42        tarpath = Base::GetTmpDir() + tarname;
43        WRITE_LOG(LOG_DEBUG, "tarpath:%s", tarpath.c_str());
44        Compress c;
45        c.UpdataPrefix(sdir);
46        c.AddPath(sdir);
47        c.SaveToFile(tarpath);
48    }
49    return tarpath;
50}
51
52bool HdcHostApp::BeginInstall(CtxFile *context, const char *command)
53{
54    int argc = 0;
55    bool ret = false;
56    string options;
57    char **argv = Base::SplitCommandToArgs(command, &argc);
58    if (argc < 1) {
59        goto Finish;
60    }
61
62    for (int i = 0; i < argc; ++i) {
63        if (!strcmp(argv[i], CMD_OPTION_CLIENTCWD.c_str())) {
64            if (i + 1 < argc) {
65                context->transferConfig.clientCwd = argv[i + 1];
66                i += 1;  // add content index
67            }
68        } else if (!strncmp(argv[i], "-", 1)) {
69            if (options.size()) {
70                options += " ";
71            }
72            options += argv[i];
73        } else {
74            string path = argv[i];
75            ExtractRelativePath(context->transferConfig.clientCwd, path);
76            if (MatchPackageExtendName(path, ".hap") || MatchPackageExtendName(path, ".hsp")) {
77                context->taskQueue.push_back(path);
78            } else {
79                string tarpath = Dir2Tar(path.c_str());
80                if (!tarpath.empty()) {
81                    context->taskQueue.push_back(tarpath);
82                    originLocalDir = path;
83                }
84            }
85        }
86    }
87    if (!context->taskQueue.size()) {
88        LogMsg(MSG_FAIL, "Not any installation package was found");
89        goto Finish;
90    }
91    // remove repeate
92    sort(context->taskQueue.begin(), context->taskQueue.end());
93    context->taskQueue.erase(unique(context->taskQueue.begin(), context->taskQueue.end()), context->taskQueue.end());
94
95    context->transferConfig.options = options;
96    context->transferConfig.functionName = CMDSTR_APP_INSTALL;
97    ret = RunQueue(context);
98Finish:
99    if (argv) {
100        delete[](reinterpret_cast<char *>(argv));
101    }
102    return ret;
103}
104
105bool HdcHostApp::BeginSideload(CtxFile *context, const char *localPath)
106{
107    bool ret = false;
108    context->transferConfig.functionName = CMDSTR_APP_SIDELOAD;
109    context->taskQueue.push_back(localPath);
110    ret = RunQueue(context);
111    return ret;
112}
113
114bool HdcHostApp::RunQueue(CtxFile *context)
115{
116    context->localPath = context->taskQueue.back();
117    uv_fs_t *openReq = new uv_fs_t;
118    if (openReq == nullptr) {
119        LogMsg(MSG_FAIL, "HdcHostApp::RunQueue new uv_fs_t failed");
120        OnFileOpenFailed(context);
121        return false;
122    }
123    memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t));
124    openReq->data = context;
125    ++refCount;
126    uv_fs_open(loopTask, openReq, context->localPath.c_str(), O_RDONLY, 0, OnFileOpen);
127    context->master = true;
128    return true;
129}
130
131void HdcHostApp::CheckMaster(CtxFile *context)
132{
133    uv_fs_t fs = {};
134    uv_fs_fstat(nullptr, &fs, context->openFd, nullptr);
135    context->transferConfig.fileSize = fs.statbuf.st_size;
136    uv_fs_req_cleanup(&fs);
137
138    context->transferConfig.optionalName
139        = Base::GetRandomString(EXPECTED_LEN);  // Prevent the name of illegal APP leads to pm unable to install
140    if (context->localPath.find(".hap") != static_cast<size_t>(-1)) {
141        context->transferConfig.optionalName += ".hap";
142    } else if (context->localPath.find(".hsp") != static_cast<size_t>(-1)) {
143        context->transferConfig.optionalName += ".hsp";
144    } else if (context->localPath.find(".tar") != static_cast<size_t>(-1)) {
145        context->transferConfig.optionalName += ".tar";
146    } else {
147        context->transferConfig.optionalName += ".bundle";
148    }
149    string bufString = SerialStruct::SerializeToString(context->transferConfig);
150    SendToAnother(CMD_APP_CHECK, const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(bufString.c_str())),
151                  bufString.size());
152}
153
154bool HdcHostApp::CheckInstallContinue(AppModType mode, bool lastResult, const char *msg)
155{
156    string modeDesc;
157    switch (mode) {
158        case APPMOD_INSTALL:
159            modeDesc = "App install";
160            break;
161        case APPMOD_UNINSTALL:
162            modeDesc = "App uninstall";
163            break;
164        case APPMOD_SIDELOAD:
165            modeDesc = "Side load";
166            break;
167        default:
168            modeDesc = "Unknown";
169            break;
170    }
171    if (ctxNow.taskQueue.size() > 0) {
172        string path = ctxNow.taskQueue.back();
173        ctxNow.taskQueue.pop_back();
174        string::size_type pos = path.rfind(".tar");
175        if (mode == APPMOD_INSTALL && pos != string::npos) {
176            unlink(path.c_str());
177            WRITE_LOG(LOG_DEBUG, "unlink path:%s", path.c_str());
178        }
179    }
180    string path = ctxNow.localPath;
181    if (!originLocalDir.empty()) {
182        path = originLocalDir;
183    }
184    LogMsg(MSG_INFO, "%s path:%s msg:%s", modeDesc.c_str(), path.c_str(), msg + printedMsgLen);
185    printedMsgLen = strlen(msg);
186    if (singalStop || !ctxNow.taskQueue.size()) {
187        LogMsg(MSG_OK, "AppMod finish");
188        return false;
189    }
190    return RunQueue(&ctxNow);
191}
192
193bool HdcHostApp::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
194{
195    if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
196        return false;
197    }
198    bool ret = true;
199    constexpr int cmdOffset = 2;
200    switch (command) {
201        case CMD_APP_INIT: {
202            ret = BeginInstall(&ctxNow, (const char *)payload);
203            break;
204        }
205        case CMD_APP_FINISH: {
206            AppModType mode = static_cast<AppModType>(payload[0]);
207            bool result = static_cast<bool>(payload[1]);
208            string s(reinterpret_cast<char *>(payload + cmdOffset), payloadSize - cmdOffset);
209            ret = CheckInstallContinue(mode, result, s.c_str());
210            break;
211        }
212        case CMD_APP_UNINSTALL: {
213            SendToAnother(CMD_APP_UNINSTALL, payload, payloadSize);
214            ctxNow.taskQueue.push_back(reinterpret_cast<char *>(payload));  // just compatible
215            break;
216        }
217        case CMD_APP_SIDELOAD: {
218            BeginSideload(&ctxNow, (const char *)payload);
219            break;
220        }
221        default:
222            break;
223    }
224    return ret;
225};
226}
227