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 RunQueue(context);
98 ret = true;
99 Finish:
100 if (argv) {
101 delete[](reinterpret_cast<char *>(argv));
102 }
103 return ret;
104 }
105
BeginSideload(CtxFile * context,const char * localPath)106 bool HdcHostApp::BeginSideload(CtxFile *context, const char *localPath)
107 {
108 bool ret = false;
109 context->transferConfig.functionName = CMDSTR_APP_SIDELOAD;
110 context->taskQueue.push_back(localPath);
111 RunQueue(context);
112 ret = true;
113 return ret;
114 }
115
RunQueue(CtxFile * context)116 void HdcHostApp::RunQueue(CtxFile *context)
117 {
118 ++refCount;
119 context->localPath = context->taskQueue.back();
120 uv_fs_open(loopTask, &context->fsOpenReq, context->localPath.c_str(), O_RDONLY, 0, OnFileOpen);
121 context->master = true;
122 }
123
CheckMaster(CtxFile * context)124 void HdcHostApp::CheckMaster(CtxFile *context)
125 {
126 uv_fs_t fs = {};
127 uv_fs_fstat(nullptr, &fs, context->fsOpenReq.result, nullptr);
128 context->transferConfig.fileSize = fs.statbuf.st_size;
129 uv_fs_req_cleanup(&fs);
130
131 context->transferConfig.optionalName
132 = Base::GetRandomString(EXPECTED_LEN); // Prevent the name of illegal APP leads to pm unable to install
133 if (context->localPath.find(".hap") != static_cast<size_t>(-1)) {
134 context->transferConfig.optionalName += ".hap";
135 } else if (context->localPath.find(".hsp") != static_cast<size_t>(-1)) {
136 context->transferConfig.optionalName += ".hsp";
137 } else if (context->localPath.find(".tar") != static_cast<size_t>(-1)) {
138 context->transferConfig.optionalName += ".tar";
139 } else {
140 context->transferConfig.optionalName += ".bundle";
141 }
142 string bufString = SerialStruct::SerializeToString(context->transferConfig);
143 SendToAnother(CMD_APP_CHECK, const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(bufString.c_str())),
144 bufString.size());
145 }
146
CheckInstallContinue(AppModType mode,bool lastResult,const char * msg)147 bool HdcHostApp::CheckInstallContinue(AppModType mode, bool lastResult, const char *msg)
148 {
149 string modeDesc;
150 switch (mode) {
151 case APPMOD_INSTALL:
152 modeDesc = "App install";
153 break;
154 case APPMOD_UNINSTALL:
155 modeDesc = "App uninstall";
156 break;
157 case APPMOD_SIDELOAD:
158 modeDesc = "Side load";
159 break;
160 default:
161 modeDesc = "Unknown";
162 break;
163 }
164 if (ctxNow.taskQueue.size() > 0) {
165 string path = ctxNow.taskQueue.back();
166 ctxNow.taskQueue.pop_back();
167 string::size_type pos = path.rfind(".tar");
168 if (mode == APPMOD_INSTALL && pos != string::npos) {
169 unlink(path.c_str());
170 WRITE_LOG(LOG_DEBUG, "unlink path:%s", path.c_str());
171 }
172 }
173 string path = ctxNow.localPath;
174 if (!originLocalDir.empty()) {
175 path = originLocalDir;
176 }
177 LogMsg(MSG_INFO, "%s path:%s msg:%s", modeDesc.c_str(), path.c_str(), msg + printedMsgLen);
178 printedMsgLen = strlen(msg);
179 if (singalStop || !ctxNow.taskQueue.size()) {
180 LogMsg(MSG_OK, "AppMod finish");
181 return false;
182 }
183 RunQueue(&ctxNow);
184 return true;
185 }
186
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)187 bool HdcHostApp::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
188 {
189 if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
190 return false;
191 }
192 bool ret = true;
193 constexpr int cmdOffset = 2;
194 switch (command) {
195 case CMD_APP_INIT: {
196 ret = BeginInstall(&ctxNow, (const char *)payload);
197 break;
198 }
199 case CMD_APP_FINISH: {
200 AppModType mode = static_cast<AppModType>(payload[0]);
201 bool result = static_cast<bool>(payload[1]);
202 string s(reinterpret_cast<char *>(payload + cmdOffset), payloadSize - cmdOffset);
203 ret = CheckInstallContinue(mode, result, s.c_str());
204 break;
205 }
206 case CMD_APP_UNINSTALL: {
207 SendToAnother(CMD_APP_UNINSTALL, payload, payloadSize);
208 ctxNow.taskQueue.push_back(reinterpret_cast<char *>(payload)); // just compatible
209 break;
210 }
211 case CMD_APP_SIDELOAD: {
212 BeginSideload(&ctxNow, (const char *)payload);
213 break;
214 }
215 default:
216 break;
217 }
218 return ret;
219 };
220 }
221