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
18 namespace Hdc {
HdcHostApp(HTaskInfo hTaskInfo)19 HdcHostApp::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
~HdcHostApp()28 HdcHostApp::~HdcHostApp()
29 {
30 }
31
Dir2Tar(const char *dir)32 string 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
BeginInstall(CtxFile *context, const char *command)52 bool 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);
98 Finish:
99 if (argv) {
100 delete[](reinterpret_cast<char *>(argv));
101 }
102 return ret;
103 }
104
BeginSideload(CtxFile *context, const char *localPath)105 bool 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
RunQueue(CtxFile *context)114 bool 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
CheckMaster(CtxFile *context)131 void 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
CheckInstallContinue(AppModType mode, bool lastResult, const char *msg)154 bool 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
CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)193 bool 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