1 /*
2  * Copyright (c) 2023 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 
16 #include "module_utils.h"
17 #include <cerrno>
18 #include <cstdio>
19 #include <dirent.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <thread>
23 #include <fcntl.h>
24 #include "init_reboot.h"
25 #include "if_system_ability_manager.h"
26 #include "iremote_object.h"
27 #include "iservice_registry.h"
28 #include "directory_ex.h"
29 #include "log/log.h"
30 #include "parameter.h"
31 #include "parameters.h"
32 #include "singleton.h"
33 #include "utils.h"
34 #include "module_constants.h"
35 #include "module_file.h"
36 
37 namespace OHOS {
38 namespace SysInstaller {
39 using namespace Updater;
40 
41 namespace {
42 constexpr const char *BOOT_COMPLETE_PARAM = "bootevent.boot.completed";
43 constexpr const char *BOOT_SUCCESS_VALUE = "true";
44 constexpr int32_t PARAM_VALUE_SIZE = 10;
45 constexpr std::chrono::milliseconds WAIT_FOR_FILE_TIME(5);
46 constexpr uint32_t BYTE_SIZE = 8;
47 constexpr mode_t ALL_PERMISSIONS = 0777;
48 constexpr const char *PREFIXES[] = {UPDATE_INSTALL_DIR, UPDATE_ACTIVE_DIR, UPDATE_BACKUP_DIR, MODULE_PREINSTALL_DIR};
49 }
50 
CreateDirIfNeeded(const std::string & path,mode_t mode)51 bool CreateDirIfNeeded(const std::string &path, mode_t mode)
52 {
53     struct stat statData;
54 
55     if (stat(path.c_str(), &statData) != 0) {
56         if (errno == ENOENT) {
57             if (mkdir(path.c_str(), mode) != 0) {
58                 LOG(ERROR) << "Could not mkdir " << path;
59                 return false;
60             }
61         } else {
62             LOG(ERROR) << "Could not stat " << path;
63             return false;
64         }
65     } else {
66         if (!S_ISDIR(statData.st_mode)) {
67             LOG(ERROR) << path << " exists and is not a directory";
68             return false;
69         }
70     }
71 
72     // Need to manually call chmod because mkdir will create a folder with
73     // permissions mode & ~umask.
74     if (chmod(path.c_str(), mode) != 0) {
75         LOG(WARNING) << "Could not chmod " << path;
76     }
77     return true;
78 }
79 
CheckPathExists(const std::string & path)80 bool CheckPathExists(const std::string &path)
81 {
82     struct stat buffer;
83     return stat(path.c_str(), &buffer) == 0;
84 }
85 
CheckFileSuffix(const std::string & file,const std::string & suffix)86 bool CheckFileSuffix(const std::string &file, const std::string &suffix)
87 {
88     std::size_t pos = file.find_last_of('.');
89     if (pos == std::string::npos) {
90         LOG(ERROR) << "Invalid file name " << file;
91         return false;
92     }
93     std::string fileSuffix = file.substr(pos);
94     return fileSuffix == suffix;
95 }
96 
GetFileName(const std::string & file)97 std::string GetFileName(const std::string &file)
98 {
99     std::size_t startPos = file.find_last_of('/') + 1;
100     std::size_t endPos = file.find_last_of('.');
101     return file.substr(startPos, endPos - startPos);
102 }
103 
104 // Get hmpName from path such as "/data/module_update_package/hmpName/sa1.zip"
GetHmpName(const std::string & filePath)105 std::string GetHmpName(const std::string &filePath)
106 {
107     std::size_t endPos = filePath.find_last_of('/');
108     if (endPos == std::string::npos) {
109         LOG(ERROR) << "Invalid package path " << filePath;
110         return "";
111     }
112 
113     std::size_t startPos = 0;
114     for (auto &iter : PREFIXES) {
115         if (StartsWith(filePath, iter)) {
116             startPos = strlen(iter) + 1;
117             break;
118         }
119     }
120     if (startPos == 0 || startPos >= endPos) {
121         LOG(ERROR) << "Invalid package path " << filePath;
122         return "";
123     }
124     return filePath.substr(startPos, endPos - startPos);
125 }
126 
WaitForFile(const std::string & path,const std::chrono::nanoseconds & timeout)127 bool WaitForFile(const std::string &path, const std::chrono::nanoseconds &timeout)
128 {
129     Timer timer;
130     bool hasSlept = false;
131     while (timer.duration() < timeout) {
132         struct stat buffer;
133         if (stat(path.c_str(), &buffer) != -1) {
134             if (hasSlept) {
135                 LOG(INFO) << "wait for '" << path << "' took " << timer;
136             }
137             return true;
138         }
139         std::this_thread::sleep_for(WAIT_FOR_FILE_TIME);
140         hasSlept = true;
141     }
142     LOG(ERROR) << "wait for '" << path << "' timed out and took " << timer;
143     return false;
144 }
145 
StartsWith(const std::string & str,const std::string & prefix)146 bool StartsWith(const std::string &str, const std::string &prefix)
147 {
148     return str.substr(0, prefix.size()) == prefix;
149 }
150 
ReadFullyAtOffset(int fd,uint8_t * data,size_t count,off_t offset)151 bool ReadFullyAtOffset(int fd, uint8_t *data, size_t count, off_t offset)
152 {
153     while (count > 0) {
154         ssize_t readSize = pread(fd, data, count, offset);
155         if (readSize <= 0) {
156             return false;
157         }
158         data += readSize;
159         count -= static_cast<size_t>(readSize);
160         offset += readSize;
161     }
162     return true;
163 }
164 
ReadLE16(const uint8_t * buff)165 uint16_t ReadLE16(const uint8_t *buff)
166 {
167     if (buff == nullptr) {
168         LOG(ERROR) << "buff is null";
169         return 0;
170     }
171     uint16_t value16 = buff[0];
172     value16 += static_cast<uint16_t>(buff[1] << BYTE_SIZE);
173     return value16;
174 }
175 
ReadLE32(const uint8_t * buff)176 uint32_t ReadLE32(const uint8_t *buff)
177 {
178     if (buff == nullptr) {
179         LOG(ERROR) << "buff is null";
180         return 0;
181     }
182     uint16_t low = ReadLE16(buff);
183     uint16_t high = ReadLE16(buff + sizeof(uint16_t));
184     uint32_t value = ((static_cast<uint32_t>(high)) << (BYTE_SIZE * sizeof(uint16_t))) | low;
185     return value;
186 }
187 
operator <<(std::ostream & os,const Timer & timer)188 std::ostream &operator<<(std::ostream &os, const Timer &timer)
189 {
190     os << timer.duration().count() << "ms";
191     return os;
192 }
193 
GetRealPath(const std::string & filePath)194 std::string GetRealPath(const std::string &filePath)
195 {
196     char path[PATH_MAX] = {'\0'};
197     if (realpath(filePath.c_str(), path) == nullptr) {
198         LOG(ERROR) << "get real path fail " << filePath;
199         return "";
200     }
201     if (!CheckPathExists(path)) {
202         LOG(ERROR) << "path " << path << " doesn't exist";
203         return "";
204     }
205     std::string realPath(path);
206     return realPath;
207 }
208 
Revert(const std::string & hmpName,bool reboot)209 void Revert(const std::string &hmpName, bool reboot)
210 {
211     LOG(INFO) << "RevertAndReboot, reboot: " << reboot;
212     std::string installPath = std::string(UPDATE_INSTALL_DIR) + "/" + hmpName;
213     if (CheckPathExists(installPath)) {
214         if (!ForceRemoveDirectory(installPath)) {
215             LOG(ERROR) << "Failed to remove installPath: " << installPath;
216             return;
217         }
218     }
219     struct stat statData;
220     std::string activePath = std::string(UPDATE_ACTIVE_DIR) + "/" + hmpName;
221     int ret = stat(activePath.c_str(), &statData);
222     if (ret != 0) {
223         LOG(ERROR) << "Failed to access " << activePath << " err=" << errno;
224         return;
225     }
226     if (!ForceRemoveDirectory(activePath)) {
227         LOG(ERROR) << "Failed to remove " << activePath;
228         return;
229     }
230 
231     std::string backupPath = std::string(UPDATE_BACKUP_DIR) + "/" + hmpName;
232     if (CheckPathExists(backupPath)) {
233         ret = rename(backupPath.c_str(), activePath.c_str());
234         if (ret != 0) {
235             LOG(ERROR) << "Failed to rename " << backupPath << " to " << activePath << " err=" << errno;
236         }
237         if (ret == 0 && chmod(activePath.c_str(), statData.st_mode & ALL_PERMISSIONS) != 0) {
238             LOG(ERROR) << "Failed to restore original permissions for " << activePath << " err=" << errno;
239         }
240     }
241     sync();
242     if (reboot) {
243         LOG(INFO) << "Rebooting";
244         DoReboot("");
245     }
246 }
247 
IsHotSa(int32_t saId)248 bool IsHotSa(int32_t saId)
249 {
250     std::vector<int32_t> onDemandSaIds;
251     sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
252     if (samgr == nullptr) {
253         LOG(ERROR) << "get system ability manager error";
254         return false;
255     }
256     samgr->GetOnDemandSystemAbilityIds(onDemandSaIds);
257     if (onDemandSaIds.empty()) {
258         LOG(ERROR) << "get ondemand saIds fail";
259         return false;
260     }
261     if (find(onDemandSaIds.begin(), onDemandSaIds.end(), saId) == onDemandSaIds.end()) {
262         LOG(INFO) << "this is not an ondemand sa, saId=" << saId;
263         return false;
264     }
265     return true;
266 }
267 
IsRunning(int32_t saId)268 bool IsRunning(int32_t saId)
269 {
270     sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
271     if (samgr == nullptr) {
272         LOG(ERROR) << "get system ability manager error";
273         return false;
274     }
275     auto object = samgr->CheckSystemAbility(saId);
276     if (object == nullptr) {
277         LOG(INFO) << "sa not exists, saId=" << saId;
278         return false;
279     }
280     return true;
281 }
282 
CheckBootComplete(void)283 bool CheckBootComplete(void)
284 {
285     char value[PARAM_VALUE_SIZE] = "";
286     int ret = GetParameter(BOOT_COMPLETE_PARAM, "", value, PARAM_VALUE_SIZE);
287     if (ret < 0) {
288         LOG(ERROR) << "Failed to get parameter " << BOOT_COMPLETE_PARAM;
289         return false;
290     }
291     return strcmp(value, BOOT_SUCCESS_VALUE) == 0;
292 }
293 
IsHotHmpPackage(int32_t type)294 bool IsHotHmpPackage(int32_t type)
295 {
296     return false;
297 }
298 
IsHotHmpPackage(const std::string & hmpName)299 bool IsHotHmpPackage(const std::string &hmpName)
300 {
301     std::string preInstalledPath = std::string(MODULE_PREINSTALL_DIR) + "/" + hmpName + "/" + HMP_INFO_NAME;
302     if (!Utils::IsFileExist(preInstalledPath)) {
303         LOG(ERROR) << "preInstalled hmp is not exist: " << preInstalledPath;
304         return false;
305     }
306     std::unique_ptr<ModuleFile> preInstalledFile = ModuleFile::Open(preInstalledPath);
307     if (preInstalledFile == nullptr) {
308         LOG(ERROR) << "preInstalled file is invalid: " << preInstalledPath;
309         return false;
310     }
311     return IsHotHmpPackage(static_cast<int32_t>(preInstalledFile->GetHmpPackageType()));
312 }
313 
GetDeviceSaSdkVersion(void)314 std::string GetDeviceSaSdkVersion(void)
315 {
316     std::string sdkVersion = system::GetParameter("const.build.sa_sdk_version", "");
317     if (sdkVersion.empty()) {
318         LOG(ERROR) << "get device sa sdk version failed.";
319         return sdkVersion;
320     }
321     return sdkVersion;
322 }
323 
GetDeviceApiVersion(void)324 int GetDeviceApiVersion(void)
325 {
326     std::string apiVersion = system::GetParameter("const.ohos.apiversion", "");
327     if (apiVersion.empty()) {
328         LOG(ERROR) << "get device api version failed.";
329         return 0;
330     }
331     return Utils::String2Int<int>(apiVersion, Utils::N_DEC);
332 }
333 
GetContentFromZip(const std::string & zipPath,const std::string & fileName)334 std::string GetContentFromZip(const std::string &zipPath, const std::string &fileName)
335 {
336     ModuleZipHelper helper(zipPath);
337     if (!helper.IsValid()) {
338         LOG(ERROR) << "Failed to open file: " << zipPath;
339         return "";
340     }
341     std::string content;
342     if (!ExtractZipFile(helper, fileName, content)) {
343         LOG(ERROR) << "Failed to extract: " << fileName << " from package: " << zipPath;
344         return "";
345     }
346     return content;
347 }
348 
RemoveSpecifiedDir(const std::string & path)349 void RemoveSpecifiedDir(const std::string &path)
350 {
351     if (!CheckPathExists(path)) {
352         return;
353     }
354     LOG(INFO) << "Remove specified dir: " << path;
355     if (!ForceRemoveDirectory(path)) {
356         LOG(ERROR) << "Failed to remove: " << path << ", err: " << errno;
357     }
358 }
359 
CheckAndUpdateRevertResult(const std::string & hmpPath,const std::string & resultInfo,const std::string & keyWord)360 bool CheckAndUpdateRevertResult(const std::string &hmpPath, const std::string &resultInfo, const std::string &keyWord)
361 {
362     if (resultInfo.find(keyWord) == std::string::npos) {
363         return false;
364     }
365     std::ifstream ifs { MODULE_RESULT_PATH };
366     if (!ifs.is_open()) {
367         LOG(ERROR) << "ifs open result_file fail" << strerror(errno);
368         return false;
369     }
370     std::string line;
371     std::vector<std::string> lines;
372     bool ret = false;
373     while (getline(ifs, line)) {
374         if (line.find(hmpPath) == std::string::npos) {
375             lines.push_back(line);
376             continue;
377         }
378         std::vector<std::string> results = Utils::SplitString(line, ";");
379         if (results.size() < 3) {  // 3: hmp|result|msg
380             LOG(ERROR) << "Split result fail: " << line;
381             continue;
382         }
383         if (results[1] != "0") {  // 1: index of result
384             lines.push_back(line);
385             continue;
386         }
387         ret = true;
388         lines.push_back(resultInfo);
389     }
390     ifs.close();
391     std::ofstream outfile(MODULE_RESULT_PATH, std::ios::binary | std::ios::trunc);
392     if (!outfile) {
393         LOG(ERROR) << "ofs open result_file fail" << strerror(errno);
394         return false;
395     }
396     for (const auto &info : lines) {
397         outfile << info;
398     }
399     LOG(INFO) << "Update revert result succ";
400     sync();
401     return ret;
402 }
403 
KillProcessOnArkWeb(void)404 void KillProcessOnArkWeb(void)
405 {
406 }
407 
InstallHmpBundle(const std::string & hmpPath,bool revert)408 bool InstallHmpBundle(const std::string &hmpPath, bool revert)
409 {
410     LOG(INFO) << "Start to install hmp bundle: " << hmpPath << " ,revert: " << revert;
411     return false;
412 }
413 } // namespace SysInstaller
414 } // namespace OHOS