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