xref: /developtools/hdc/src/daemon/daemon_app.cpp (revision cc290419)
1cc290419Sopenharmony_ci/*
2cc290419Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd.
3cc290419Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cc290419Sopenharmony_ci * you may not use this file except in compliance with the License.
5cc290419Sopenharmony_ci * You may obtain a copy of the License at
6cc290419Sopenharmony_ci *
7cc290419Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cc290419Sopenharmony_ci *
9cc290419Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cc290419Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cc290419Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cc290419Sopenharmony_ci * See the License for the specific language governing permissions and
13cc290419Sopenharmony_ci * limitations under the License.
14cc290419Sopenharmony_ci */
15cc290419Sopenharmony_ci#include "daemon_app.h"
16cc290419Sopenharmony_ci#include "decompress.h"
17cc290419Sopenharmony_ci
18cc290419Sopenharmony_cinamespace Hdc {
19cc290419Sopenharmony_ciHdcDaemonApp::HdcDaemonApp(HTaskInfo hTaskInfo)
20cc290419Sopenharmony_ci    : HdcTransferBase(hTaskInfo)
21cc290419Sopenharmony_ci{
22cc290419Sopenharmony_ci    commandBegin = CMD_APP_BEGIN;
23cc290419Sopenharmony_ci    commandData = CMD_APP_DATA;
24cc290419Sopenharmony_ci    funcAppModFinish = nullptr;
25cc290419Sopenharmony_ci}
26cc290419Sopenharmony_ci
27cc290419Sopenharmony_ciHdcDaemonApp::~HdcDaemonApp()
28cc290419Sopenharmony_ci{
29cc290419Sopenharmony_ci    WRITE_LOG(LOG_INFO, "~HdcDaemonApp channelId:%u", taskInfo->channelId);
30cc290419Sopenharmony_ci}
31cc290419Sopenharmony_ci
32cc290419Sopenharmony_cibool HdcDaemonApp::ReadyForRelease()
33cc290419Sopenharmony_ci{
34cc290419Sopenharmony_ci    if (!HdcTaskBase::ReadyForRelease()) {
35cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "HdcTaskBase not ready for release channelId:%u", taskInfo->channelId);
36cc290419Sopenharmony_ci        return false;
37cc290419Sopenharmony_ci    }
38cc290419Sopenharmony_ci    if (!asyncCommand.ReadyForRelease()) {
39cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "asyncCommand not ready for release channelId:%u", taskInfo->channelId);
40cc290419Sopenharmony_ci        return false;
41cc290419Sopenharmony_ci    }
42cc290419Sopenharmony_ci    WRITE_LOG(LOG_INFO, "ReadyForRelease channelId:%u", taskInfo->channelId);
43cc290419Sopenharmony_ci    return true;
44cc290419Sopenharmony_ci}
45cc290419Sopenharmony_ci
46cc290419Sopenharmony_civoid HdcDaemonApp::MakeCtxForAppCheck(uint8_t *payload, const int payloadSize)
47cc290419Sopenharmony_ci{
48cc290419Sopenharmony_ci    string dstPath = "/data/local/tmp/";
49cc290419Sopenharmony_ci    string bufString(reinterpret_cast<char *>(payload), payloadSize);
50cc290419Sopenharmony_ci    SerialStruct::ParseFromString(ctxNow.transferConfig, bufString);
51cc290419Sopenharmony_ci    // update transferconfig to main context
52cc290419Sopenharmony_ci    ctxNow.master = false;
53cc290419Sopenharmony_ci#ifdef HDC_PCDEBUG
54cc290419Sopenharmony_ci    char tmpPath[256] = "";
55cc290419Sopenharmony_ci    size_t size = 256;
56cc290419Sopenharmony_ci    uv_os_tmpdir(tmpPath, &size);
57cc290419Sopenharmony_ci    dstPath = tmpPath;
58cc290419Sopenharmony_ci    dstPath += Base::GetPathSep();
59cc290419Sopenharmony_ci#endif
60cc290419Sopenharmony_ci    dstPath += ctxNow.transferConfig.optionalName;
61cc290419Sopenharmony_ci    ctxNow.localPath = dstPath;
62cc290419Sopenharmony_ci    ctxNow.transferBegin = Base::GetRuntimeMSec();
63cc290419Sopenharmony_ci    ctxNow.fileSize = ctxNow.transferConfig.fileSize;
64cc290419Sopenharmony_ci    return;
65cc290419Sopenharmony_ci}
66cc290419Sopenharmony_ci
67cc290419Sopenharmony_cibool HdcDaemonApp::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
68cc290419Sopenharmony_ci{
69cc290419Sopenharmony_ci    if (!HdcTransferBase::CommandDispatch(command, payload, payloadSize)) {
70cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "HdcTransferBase::CommandDispatch false command:%u channelId:%u",
71cc290419Sopenharmony_ci            command, taskInfo->channelId);
72cc290419Sopenharmony_ci        return false;
73cc290419Sopenharmony_ci    }
74cc290419Sopenharmony_ci    bool ret = true;
75cc290419Sopenharmony_ci    switch (command) {
76cc290419Sopenharmony_ci        case CMD_APP_CHECK: {
77cc290419Sopenharmony_ci            uv_fs_t *openReq = new uv_fs_t;
78cc290419Sopenharmony_ci            if (openReq == nullptr) {
79cc290419Sopenharmony_ci                WRITE_LOG(LOG_FATAL, "HdcDaemonApp::CommandDispatch new uv_fs_t failed");
80cc290419Sopenharmony_ci                return false;
81cc290419Sopenharmony_ci            }
82cc290419Sopenharmony_ci            memset_s(openReq, sizeof(uv_fs_t), 0, sizeof(uv_fs_t));
83cc290419Sopenharmony_ci            MakeCtxForAppCheck(payload, payloadSize);
84cc290419Sopenharmony_ci            openReq->data = &ctxNow;
85cc290419Sopenharmony_ci            ++refCount;
86cc290419Sopenharmony_ci            uv_fs_open(loopTask, openReq, ctxNow.localPath.c_str(),
87cc290419Sopenharmony_ci                       UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
88cc290419Sopenharmony_ci                       OnFileOpen);
89cc290419Sopenharmony_ci            break;
90cc290419Sopenharmony_ci        }
91cc290419Sopenharmony_ci        case CMD_APP_UNINSTALL: {
92cc290419Sopenharmony_ci            // This maybe has a command implanting risk, since it is a controllable device, it can be ignored
93cc290419Sopenharmony_ci            string bufString(reinterpret_cast<char *>(payload), payloadSize);
94cc290419Sopenharmony_ci            string options = "";
95cc290419Sopenharmony_ci            string packages = "";
96cc290419Sopenharmony_ci            vector<string> segments;
97cc290419Sopenharmony_ci            Base::SplitString(bufString, " ", segments);
98cc290419Sopenharmony_ci            for (auto seg: segments) {
99cc290419Sopenharmony_ci                if (seg[0] == '-') {
100cc290419Sopenharmony_ci                    options += " " + seg;
101cc290419Sopenharmony_ci                } else {
102cc290419Sopenharmony_ci                    packages += " " + seg;
103cc290419Sopenharmony_ci                }
104cc290419Sopenharmony_ci            }
105cc290419Sopenharmony_ci            PackageShell(false, options.c_str(), packages);
106cc290419Sopenharmony_ci            break;
107cc290419Sopenharmony_ci        }
108cc290419Sopenharmony_ci        default:
109cc290419Sopenharmony_ci            break;
110cc290419Sopenharmony_ci    }
111cc290419Sopenharmony_ci    return ret;
112cc290419Sopenharmony_ci};
113cc290419Sopenharmony_ci
114cc290419Sopenharmony_cibool HdcDaemonApp::AsyncInstallFinish(bool finish, int64_t exitStatus, const string result)
115cc290419Sopenharmony_ci{
116cc290419Sopenharmony_ci    if (mode == APPMOD_INSTALL) {
117cc290419Sopenharmony_ci        unlink(ctxNow.localPath.c_str());
118cc290419Sopenharmony_ci        string::size_type rindex = ctxNow.localPath.rfind(".tar");
119cc290419Sopenharmony_ci        if (rindex != string::npos) {
120cc290419Sopenharmony_ci            string dir = ctxNow.localPath.substr(0, rindex);
121cc290419Sopenharmony_ci            RemovePath(dir);
122cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "RemovePath dir:%s", dir.c_str());
123cc290419Sopenharmony_ci        }
124cc290419Sopenharmony_ci    }
125cc290419Sopenharmony_ci    asyncCommand.DoRelease();
126cc290419Sopenharmony_ci    string echo = result;
127cc290419Sopenharmony_ci    echo = Base::ReplaceAll(echo, "\n", " ");
128cc290419Sopenharmony_ci    vector<uint8_t> vecBuf;
129cc290419Sopenharmony_ci    vecBuf.push_back(mode);
130cc290419Sopenharmony_ci    vecBuf.push_back(exitStatus == 0);
131cc290419Sopenharmony_ci    vecBuf.insert(vecBuf.end(), (uint8_t *)echo.c_str(), (uint8_t *)echo.c_str() + echo.size());
132cc290419Sopenharmony_ci    SendToAnother(CMD_APP_FINISH, vecBuf.data(), vecBuf.size());
133cc290419Sopenharmony_ci    --refCount;
134cc290419Sopenharmony_ci#ifdef UNIT_TEST
135cc290419Sopenharmony_ci    Base::WriteBinFile((UT_TMP_PATH + "/appinstall.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
136cc290419Sopenharmony_ci                       MESSAGE_SUCCESS.size(), true);
137cc290419Sopenharmony_ci#endif
138cc290419Sopenharmony_ci    return true;
139cc290419Sopenharmony_ci}
140cc290419Sopenharmony_ci
141cc290419Sopenharmony_civoid HdcDaemonApp::PackageShell(bool installOrUninstall, const char *options, const string package)
142cc290419Sopenharmony_ci{
143cc290419Sopenharmony_ci    ++refCount;
144cc290419Sopenharmony_ci    // asynccmd Other processes, no RunningProtect protection
145cc290419Sopenharmony_ci    chmod(package.c_str(), 0755);
146cc290419Sopenharmony_ci    string doBuf;
147cc290419Sopenharmony_ci    string opts = string(options);
148cc290419Sopenharmony_ci    if (installOrUninstall) { // either -p or -s is always required in install
149cc290419Sopenharmony_ci        if (opts.find("p") == string::npos && opts.find("s") == string::npos) {
150cc290419Sopenharmony_ci            // basic mode: blank options or both "-s" / "-p" are omitted
151cc290419Sopenharmony_ci            // eg. hdc install x.hap --> bm install -p x.hap
152cc290419Sopenharmony_ci            // eg. hdc install -r x.hap --> bm install -r -p x.hap
153cc290419Sopenharmony_ci            doBuf = Base::StringFormat("bm install %s -p %s", options, package.c_str());
154cc290419Sopenharmony_ci        } else {
155cc290419Sopenharmony_ci            // advansed mode for -p/-r/-s and some other options in the future
156cc290419Sopenharmony_ci            doBuf = Base::StringFormat("bm install %s %s", options, package.c_str());
157cc290419Sopenharmony_ci        }
158cc290419Sopenharmony_ci    } else {  // -n is always required in uninstall
159cc290419Sopenharmony_ci        if (opts.find("n") == string::npos) {
160cc290419Sopenharmony_ci            // basic mode: blank options or "-n" is omitted
161cc290419Sopenharmony_ci            // eg. hdc uninstall com.xx.xx --> bm uninstall -n com.xx.xx
162cc290419Sopenharmony_ci            // eg. hdc uninstall -s com.xx.xx --> bm uninstall -s -n com.xx.xx
163cc290419Sopenharmony_ci            doBuf = Base::StringFormat("bm uninstall %s -n %s", options, package.c_str());
164cc290419Sopenharmony_ci        } else {
165cc290419Sopenharmony_ci            // advansed mode for -s/-n and some other options in the future
166cc290419Sopenharmony_ci            doBuf = Base::StringFormat("bm uninstall %s %s", options, package.c_str());
167cc290419Sopenharmony_ci        }
168cc290419Sopenharmony_ci    }
169cc290419Sopenharmony_ci
170cc290419Sopenharmony_ci    funcAppModFinish = [this](bool finish, int64_t exitStatus, const string result) -> bool {
171cc290419Sopenharmony_ci        return this->AsyncInstallFinish(finish, exitStatus, result);
172cc290419Sopenharmony_ci    };
173cc290419Sopenharmony_ci    if (installOrUninstall) {
174cc290419Sopenharmony_ci        mode = APPMOD_INSTALL;
175cc290419Sopenharmony_ci    } else {
176cc290419Sopenharmony_ci        mode = APPMOD_UNINSTALL;
177cc290419Sopenharmony_ci    }
178cc290419Sopenharmony_ci    asyncCommand.Initial(loopTask, funcAppModFinish, AsyncCmd::OPTION_COMMAND_ONETIME);
179cc290419Sopenharmony_ci    asyncCommand.ExecuteCommand(doBuf);
180cc290419Sopenharmony_ci}
181cc290419Sopenharmony_ci
182cc290419Sopenharmony_civoid HdcDaemonApp::Sideload(const char *pathOTA)
183cc290419Sopenharmony_ci{
184cc290419Sopenharmony_ci    mode = APPMOD_SIDELOAD;
185cc290419Sopenharmony_ci    LogMsg(MSG_OK, "[placeholders] sideload %s", pathOTA);
186cc290419Sopenharmony_ci    TaskFinish();
187cc290419Sopenharmony_ci    unlink(pathOTA);
188cc290419Sopenharmony_ci}
189cc290419Sopenharmony_ci
190cc290419Sopenharmony_cistring HdcDaemonApp::Tar2Dir(const char *path)
191cc290419Sopenharmony_ci{
192cc290419Sopenharmony_ci    string dir;
193cc290419Sopenharmony_ci    string tarpath = path;
194cc290419Sopenharmony_ci    string::size_type rindex = tarpath.rfind(".tar");
195cc290419Sopenharmony_ci    if (rindex != string::npos) {
196cc290419Sopenharmony_ci        dir = tarpath.substr(0, rindex) + Base::GetPathSep();
197cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "path:%s dir:%s", path, dir.c_str());
198cc290419Sopenharmony_ci        Decompress dc(tarpath);
199cc290419Sopenharmony_ci        dc.DecompressToLocal(dir);
200cc290419Sopenharmony_ci    }
201cc290419Sopenharmony_ci    return dir;
202cc290419Sopenharmony_ci}
203cc290419Sopenharmony_ci
204cc290419Sopenharmony_ciint HdcDaemonApp::RemoveDir(const string &dir)
205cc290419Sopenharmony_ci{
206cc290419Sopenharmony_ci    DIR *pdir = opendir(dir.c_str());
207cc290419Sopenharmony_ci    if (pdir == nullptr) {
208cc290419Sopenharmony_ci        WRITE_LOG(LOG_FATAL, "opendir failed dir:%s", dir.c_str());
209cc290419Sopenharmony_ci        return -1;
210cc290419Sopenharmony_ci    }
211cc290419Sopenharmony_ci    struct dirent *ent;
212cc290419Sopenharmony_ci    struct stat st;
213cc290419Sopenharmony_ci    while ((ent = readdir(pdir)) != nullptr) {
214cc290419Sopenharmony_ci        if (ent->d_name[0] == '.') {
215cc290419Sopenharmony_ci            continue;
216cc290419Sopenharmony_ci        }
217cc290419Sopenharmony_ci        std::string subpath = dir + Base::GetPathSep() + ent->d_name;
218cc290419Sopenharmony_ci        if (lstat(subpath.c_str(), &st) == -1) {
219cc290419Sopenharmony_ci            WRITE_LOG(LOG_WARN, "lstat failed subpath:%s", subpath.c_str());
220cc290419Sopenharmony_ci            continue;
221cc290419Sopenharmony_ci        }
222cc290419Sopenharmony_ci        if (S_ISDIR(st.st_mode)) {
223cc290419Sopenharmony_ci            if (RemoveDir(subpath) == -1) {
224cc290419Sopenharmony_ci                closedir(pdir);
225cc290419Sopenharmony_ci                return -1;
226cc290419Sopenharmony_ci            }
227cc290419Sopenharmony_ci            rmdir(subpath.c_str());
228cc290419Sopenharmony_ci        } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
229cc290419Sopenharmony_ci            unlink(subpath.c_str());
230cc290419Sopenharmony_ci        } else {
231cc290419Sopenharmony_ci            WRITE_LOG(LOG_DEBUG, "lstat st_mode:%07o subpath:%s", st.st_mode, subpath.c_str());
232cc290419Sopenharmony_ci        }
233cc290419Sopenharmony_ci    }
234cc290419Sopenharmony_ci    if (rmdir(dir.c_str()) == -1) {
235cc290419Sopenharmony_ci        closedir(pdir);
236cc290419Sopenharmony_ci        return -1;
237cc290419Sopenharmony_ci    }
238cc290419Sopenharmony_ci    closedir(pdir);
239cc290419Sopenharmony_ci    return 0;
240cc290419Sopenharmony_ci}
241cc290419Sopenharmony_ci
242cc290419Sopenharmony_civoid HdcDaemonApp::RemovePath(const string &path)
243cc290419Sopenharmony_ci{
244cc290419Sopenharmony_ci    struct stat st;
245cc290419Sopenharmony_ci    if (lstat(path.c_str(), &st) == -1) {
246cc290419Sopenharmony_ci        WRITE_LOG(LOG_WARN, "lstat failed path:%s", path.c_str());
247cc290419Sopenharmony_ci        return;
248cc290419Sopenharmony_ci    }
249cc290419Sopenharmony_ci    if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
250cc290419Sopenharmony_ci        unlink(path.c_str());
251cc290419Sopenharmony_ci    } else if (S_ISDIR(st.st_mode)) {
252cc290419Sopenharmony_ci        if (path == "." || path == "..") {
253cc290419Sopenharmony_ci            return;
254cc290419Sopenharmony_ci        }
255cc290419Sopenharmony_ci        int rc = RemoveDir(path);
256cc290419Sopenharmony_ci        WRITE_LOG(LOG_INFO, "RemoveDir rc:%d path:%s", rc, path.c_str());
257cc290419Sopenharmony_ci    }
258cc290419Sopenharmony_ci}
259cc290419Sopenharmony_ci
260cc290419Sopenharmony_civoid HdcDaemonApp::WhenTransferFinish(CtxFile *context)
261cc290419Sopenharmony_ci{
262cc290419Sopenharmony_ci    if (context->lastErrno > 0) {
263cc290419Sopenharmony_ci        constexpr int bufSize = 1024;
264cc290419Sopenharmony_ci        char buf[bufSize] = { 0 };
265cc290419Sopenharmony_ci        uv_strerror_r(static_cast<int>(-context->lastErrno), buf, bufSize);
266cc290419Sopenharmony_ci        WRITE_LOG(LOG_DEBUG, "HdcDaemonApp WhenTransferFinish with errno:%d", context->lastErrno);
267cc290419Sopenharmony_ci        LogMsg(MSG_FAIL, "Transfer App at:%lld/%lld(Bytes), Reason: %s",
268cc290419Sopenharmony_ci               context->indexIO, context->fileSize, buf);
269cc290419Sopenharmony_ci        return;
270cc290419Sopenharmony_ci    }
271cc290419Sopenharmony_ci    if (ctxNow.transferConfig.functionName == CMDSTR_APP_SIDELOAD) {
272cc290419Sopenharmony_ci        Sideload(context->localPath.c_str());
273cc290419Sopenharmony_ci    } else if (ctxNow.transferConfig.functionName == CMDSTR_APP_INSTALL) {
274cc290419Sopenharmony_ci        string dir = Tar2Dir(context->localPath.c_str());
275cc290419Sopenharmony_ci        if (!dir.empty()) {
276cc290419Sopenharmony_ci            PackageShell(true, context->transferConfig.options.c_str(), dir.c_str());
277cc290419Sopenharmony_ci        } else {
278cc290419Sopenharmony_ci            PackageShell(true, context->transferConfig.options.c_str(), context->localPath.c_str());
279cc290419Sopenharmony_ci        }
280cc290419Sopenharmony_ci    } else {
281cc290419Sopenharmony_ci    }
282cc290419Sopenharmony_ci};
283cc290419Sopenharmony_ci}
284