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
17 namespace Hdc {
HdcHostApp(HTaskInfo hTaskInfo)18 HdcHostApp::HdcHostApp(HTaskInfo hTaskInfo)
19 : HdcTransferBase(hTaskInfo)
20 {
21 commandBegin = CMD_APP_BEGIN;
22 commandData = CMD_APP_DATA;
23 }
24
~HdcHostApp()25 HdcHostApp::~HdcHostApp()
26 {
27 }
28
BeginInstall(CtxFile * context,const char * command)29 bool HdcHostApp::BeginInstall(CtxFile *context, const char *command)
30 {
31 int argc = 0;
32 bool ret = false;
33 string options;
34 char **argv = Base::SplitCommandToArgs(command, &argc);
35 if (argc < 1) {
36 goto Finish;
37 }
38
39 for (int i = 0; i < argc; ++i) {
40 if (!strcmp(argv[i], CMD_OPTION_CLIENTCWD.c_str())) {
41 if (i + 1 < argc) {
42 context->transferConfig.clientCwd = argv[i + 1];
43 i += 1; // add content index
44 }
45 } else if (!strncmp(argv[i], "-", 1)) {
46 if (options.size()) {
47 options += " ";
48 }
49 options += argv[i];
50 } else {
51 string path = argv[i];
52 ExtractRelativePath(context->transferConfig.clientCwd, path);
53 if (MatchPackageExtendName(path, ".hap") || MatchPackageExtendName(path, ".hsp")) {
54 context->taskQueue.push_back(path);
55 } else {
56 GetSubFiles(argv[i], ".hap", &context->taskQueue);
57 GetSubFiles(argv[i], ".hsp", &context->taskQueue);
58 }
59 }
60 }
61 if (!context->taskQueue.size()) {
62 LogMsg(MSG_FAIL, "Not any installation package was found");
63 goto Finish;
64 }
65 // remove repeate
66 sort(context->taskQueue.begin(), context->taskQueue.end());
67 context->taskQueue.erase(unique(context->taskQueue.begin(), context->taskQueue.end()), context->taskQueue.end());
68
69 context->transferConfig.options = options;
70 context->transferConfig.functionName = CMDSTR_APP_INSTALL;
71 RunQueue(context);
72 ret = true;
73 Finish:
74 if (argv) {
75 delete[](reinterpret_cast<char *>(argv));
76 }
77 return ret;
78 }
79
BeginSideload(CtxFile * context,const char * localPath)80 bool HdcHostApp::BeginSideload(CtxFile *context, const char *localPath)
81 {
82 bool ret = false;
83 context->transferConfig.functionName = CMDSTR_APP_SIDELOAD;
84 context->taskQueue.push_back(localPath);
85 RunQueue(context);
86 ret = true;
87 return ret;
88 }
89
RunQueue(CtxFile * context)90 void HdcHostApp::RunQueue(CtxFile *context)
91 {
92 ++refCount;
93 context->localPath = context->taskQueue.back();
94 uv_fs_open(loopTask, &context->fsOpenReq, context->localPath.c_str(), O_RDONLY, 0, OnFileOpen);
95 context->master = true;
96 }
97
CheckMaster(CtxFile * context)98 void HdcHostApp::CheckMaster(CtxFile *context)
99 {
100 uv_fs_t fs = {};
101 uv_fs_fstat(nullptr, &fs, context->fsOpenReq.result, nullptr);
102 context->transferConfig.fileSize = fs.statbuf.st_size;
103 uv_fs_req_cleanup(&fs);
104
105 context->transferConfig.optionalName
106 = Base::GetRandomString(EXPECTED_LEN); // Prevent the name of illegal APP leads to pm unable to install
107 if (context->localPath.find(".hap") != static_cast<size_t>(-1)) {
108 context->transferConfig.optionalName += ".hap";
109 } else if (context->localPath.find(".hsp") != static_cast<size_t>(-1)) {
110 context->transferConfig.optionalName += ".hsp";
111 } else {
112 context->transferConfig.optionalName += ".bundle";
113 }
114 string bufString = SerialStruct::SerializeToString(context->transferConfig);
115 SendToAnother(CMD_APP_CHECK, const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(bufString.c_str())),
116 bufString.size());
117 }
118
CheckInstallContinue(AppModType mode,bool lastResult,const char * msg)119 bool HdcHostApp::CheckInstallContinue(AppModType mode, bool lastResult, const char *msg)
120 {
121 string modeDesc;
122 switch (mode) {
123 case APPMOD_INSTALL:
124 modeDesc = "App install";
125 break;
126 case APPMOD_UNINSTALL:
127 modeDesc = "App uninstall";
128 break;
129 case APPMOD_SIDELOAD:
130 modeDesc = "Side load";
131 break;
132 default:
133 modeDesc = "Unknown";
134 break;
135 }
136 if (ctxNow.taskQueue.size() > 0) {
137 ctxNow.taskQueue.pop_back();
138 }
139 LogMsg(MSG_INFO, "%s path:%s, queuesize:%d, msg:%s", modeDesc.c_str(), ctxNow.localPath.c_str(),
140 ctxNow.taskQueue.size(), msg + printedMsgLen);
141 printedMsgLen = strlen(msg);
142 if (singalStop || !ctxNow.taskQueue.size()) {
143 LogMsg(MSG_OK, "AppMod finish");
144 return false;
145 }
146 RunQueue(&ctxNow);
147 return true;
148 }
149
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)150 bool HdcHostApp::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
151 {
152 if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
153 return false;
154 }
155 bool ret = true;
156 constexpr int cmdOffset = 2;
157 switch (command) {
158 case CMD_APP_INIT: {
159 ret = BeginInstall(&ctxNow, (const char *)payload);
160 break;
161 }
162 case CMD_APP_FINISH: {
163 AppModType mode = static_cast<AppModType>(payload[0]);
164 bool result = static_cast<bool>(payload[1]);
165 string s(reinterpret_cast<char *>(payload + cmdOffset), payloadSize - cmdOffset);
166 ret = CheckInstallContinue(mode, result, s.c_str());
167 break;
168 }
169 case CMD_APP_UNINSTALL: {
170 SendToAnother(CMD_APP_UNINSTALL, payload, payloadSize);
171 ctxNow.taskQueue.push_back(reinterpret_cast<char *>(payload)); // just compatible
172 break;
173 }
174 case CMD_APP_SIDELOAD: {
175 BeginSideload(&ctxNow, (const char *)payload);
176 break;
177 }
178 default:
179 break;
180 }
181 return ret;
182 };
183 }
184