1 /*
2 * Copyright (c) 2024 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 "version_normalize.h"
17
18 #include "hap_packager.h"
19 #include "hqf_packager.h"
20 #include "hsp_packager.h"
21 #include "json/json_utils.h"
22 #include "json/normalize_version_utils.h"
23 #include "json/pack_info.h"
24 #include "log.h"
25 #include "utils.h"
26 #include "zip_utils.h"
27
28 namespace OHOS {
29 namespace AppPackingTool {
VersionNormalize(const std::map<std::string,std::string> & parameterMap,std::string & resultReceiver)30 VersionNormalize::VersionNormalize(const std::map<std::string, std::string> ¶meterMap, std::string &resultReceiver)
31 : Packager(parameterMap, resultReceiver)
32 {}
33
InitAllowedParam()34 int32_t VersionNormalize::InitAllowedParam()
35 {
36 allowedParameters_ = {
37 {}
38 };
39 return ERR_OK;
40 }
41
PreProcess()42 int32_t VersionNormalize::PreProcess()
43 {
44 if (!IsOutDirectoryValid()) {
45 return ERR_INVALID_VALUE;
46 }
47 auto it = parameterMap_.find(Constants::PARAM_INPUT_LIST);
48 if (it == parameterMap_.end()) {
49 LOGE("Input input-list is empty.");
50 return ERR_INVALID_VALUE;
51 }
52 if (!CompatibleProcess(it->second, hspOrhapList_, Constants::HAP_SUFFIX, Constants::HSP_SUFFIX)) {
53 LOGE("Input input-list is invalid.");
54 return ERR_INVALID_VALUE;
55 }
56 if (hspOrhapList_.size() == 0) {
57 LOGE("Input input-list is empty.");
58 return ERR_INVALID_VALUE;
59 }
60
61 it = parameterMap_.find(Constants::PARAM_VERSION_NAME);
62 std::regex pattern(Constants::VERSION_NAME_PATTERN);
63 if (it == parameterMap_.end()) {
64 LOGE("Input version-name is empty.");
65 return ERR_INVALID_VALUE;
66 } else if (!std::regex_match(it->second, pattern)) {
67 LOGE("Input version-name is not valid.");
68 return ERR_INVALID_VALUE;
69 }
70
71 it = parameterMap_.find(Constants::PARAM_VERSION_CODE);
72 if (it == parameterMap_.end()) {
73 LOGE("Input version-code is empty.");
74 return ERR_INVALID_VALUE;
75 } else if (!Utils::IsPositiveInteger(it->second)) {
76 LOGE("Input version-code is invalid.");
77 return ERR_INVALID_VALUE;
78 }
79 return ERR_OK;
80 }
81
VerifyModuleVersion(const NormalizeVersion & normalizeVersion,const int32_t & newVersionCode,const std::string & newVersionName)82 bool VersionNormalize::VerifyModuleVersion(const NormalizeVersion &normalizeVersion, const int32_t &newVersionCode,
83 const std::string &newVersionName)
84 {
85 if (normalizeVersion.originVersionCode > newVersionCode) {
86 LOGE("VersionNormalize failed, input version code less than module %s version code.",
87 normalizeVersion.moduleName.c_str());
88 return false;
89 } else if (normalizeVersion.originVersionCode == newVersionCode) {
90 LOGW("VersionNormalize warning: module %s version code not changed.", normalizeVersion.moduleName.c_str());
91 }
92 if (normalizeVersion.originVersionName == newVersionName) {
93 LOGW("VersionNormalize warning: module %s version name not changed.", normalizeVersion.moduleName.c_str());
94 }
95 return true;
96 }
97
ModifyModuleJson(const std::string & moduleJsonPath,NormalizeVersion & normalizeVersion,const int32_t & newVersionCode,const std::string & newVersionName)98 bool VersionNormalize::ModifyModuleJson(const std::string &moduleJsonPath, NormalizeVersion &normalizeVersion,
99 const int32_t &newVersionCode, const std::string &newVersionName)
100 {
101 ModuleJson moduleJson;
102 if (!moduleJson.ParseFromFile(moduleJsonPath)) {
103 LOGE("Parse and modify module.json failed, parse module.json is null.");
104 return false;
105 }
106 if (!moduleJson.GetNormalizeVersion(normalizeVersion, true)) {
107 LOGE("Parse and modify module.json failed, write Json failed.");
108 return false;
109 }
110 if (!moduleJson.SetVersionCodeAndName(newVersionCode, newVersionName, true)) {
111 LOGE("Parse and modify module.json failed, json file not valid.");
112 return false;
113 }
114 if (!JsonUtils::StrToFile(moduleJson.ToString(), moduleJsonPath)) {
115 LOGE("Parse and modify module.json failed, write Json failed.");
116 return false;
117 }
118 return true;
119 }
120
ModifyConfigJson(const std::string & configJsonPath,NormalizeVersion & normalizeVersion,const int32_t & newVersionCode,const std::string & newVersionName)121 bool VersionNormalize::ModifyConfigJson(const std::string &configJsonPath, NormalizeVersion &normalizeVersion,
122 const int32_t &newVersionCode, const std::string &newVersionName)
123 {
124 ModuleJson configJson;
125 if (!configJson.ParseFromFile(configJsonPath)) {
126 LOGE("Parse and modify config.json failed, parse json is null.");
127 return false;
128 }
129 if (!configJson.GetNormalizeVersion(normalizeVersion, false)) {
130 LOGE("Parse and modify config.json failed, json file not valid.");
131 return false;
132 }
133 if (!configJson.SetVersionCodeAndName(newVersionCode, newVersionName, false)) {
134 LOGE("Parse and modify config.json failed, json file not valid.");
135 return false;
136 }
137 if (!JsonUtils::StrToFile(configJson.ToString(), configJsonPath)) {
138 LOGE("Parse and modify config.json failed, writeJson failed.");
139 return false;
140 }
141 return true;
142 }
143
ModifyPackInfo(const std::string & packInfoPath,const int32_t & newVersionCode,const std::string & newVersionName)144 bool VersionNormalize::ModifyPackInfo(const std::string &packInfoPath, const int32_t &newVersionCode,
145 const std::string &newVersionName)
146 {
147 PackInfo packInfo;
148 if (!packInfo.ParseFromFile(packInfoPath)) {
149 LOGW("Parse and modify packInfo failed, json format invalid.");
150 return false;
151 }
152 if (!packInfo.SetVersionCode(newVersionCode)) {
153 LOGW("Parse and modify packInfo failed, version code invalid.");
154 return false;
155 }
156 if (!packInfo.SetVersionName(newVersionName)) {
157 LOGW("Parse and modify packInfo failed, version name invalid.");
158 return false;
159 }
160
161 if (!JsonUtils::StrToFile(packInfo.ToString(), packInfoPath)) {
162 LOGW("Parse and modify packInfo failed, writeJson failed.");
163 return false;
164 }
165 return true;
166 }
167
CompressDirToHap(const std::string & sourceDir,const std::string & zipFilePath)168 bool VersionNormalize::CompressDirToHap(const std::string &sourceDir, const std::string &zipFilePath)
169 {
170 std::map<std::string, std::string> parameterMap;
171 std::string resultReceiver = "";
172 parameterMap[Constants::PARAM_OUT_PATH] = zipFilePath;
173 std::unique_ptr<Packager> packager = nullptr;
174 for (const auto& entry : fs::directory_iterator(fs::path(sourceDir))) {
175 std::string fileName = entry.path().filename().string();
176 std::string filePath = entry.path().string();
177 if (fileName == Constants::ETS_PATH) {
178 parameterMap[Constants::PARAM_ETS_PATH] = filePath;
179 } else if (fileName == Constants::HNP_PATH) {
180 parameterMap[Constants::PARAM_HNP_PATH] = filePath;
181 } else if (fileName == Constants::LIB_PATH) {
182 parameterMap[Constants::PARAM_LIB_PATH] = filePath;
183 } else if (fileName == Constants::AN_PATH) {
184 parameterMap[Constants::PARAM_AN_PATH] = filePath;
185 } else if (fileName == Constants::AP_PATH) {
186 parameterMap[Constants::PARAM_AP_PATH] = filePath;
187 } else if (fileName == Constants::RESOURCES_PATH) {
188 parameterMap[Constants::PARAM_RESOURCES_PATH] = filePath;
189 } else if (fileName == Constants::JS_PATH) {
190 parameterMap[Constants::PARAM_JS_PATH] = filePath;
191 } else if (fileName == Constants::ASSETS_PATH) {
192 parameterMap[Constants::PARAM_ASSETS_PATH] = filePath;
193 } else if (fileName == Constants::SO_DIR) {
194 parameterMap[Constants::PARAM_MAPLE_SO_DIR] = filePath;
195 } else if (fileName == Constants::SHARED_LIBS_DIR) {
196 parameterMap[Constants::PARAM_SHAREDLIBS_PATH] = filePath;
197 } else if (fileName == Constants::CONFIG_JSON) {
198 parameterMap[Constants::PARAM_JSON_PATH] = filePath;
199 } else if (fileName == Constants::MODULE_JSON) {
200 parameterMap[Constants::PARAM_JSON_PATH] = filePath;
201 } else if (fileName == Constants::RESOURCES_INDEX) {
202 parameterMap[Constants::PARAM_INDEX_PATH] = filePath;
203 } else if (fileName == Constants::PACK_INFO) {
204 parameterMap[Constants::PARAM_PACK_INFO_PATH] = filePath;
205 } else if (fileName == Constants::RPCID_SC) {
206 parameterMap[Constants::PARAM_RPCID_PATH] = filePath;
207 }
208 }
209 if (Utils::EndsWith(zipFilePath, Constants::HAP_SUFFIX)) {
210 packager = std::make_unique<HapPackager>(parameterMap, resultReceiver);
211 } else if (Utils::EndsWith(zipFilePath, Constants::HSP_SUFFIX)) {
212 packager = std::make_unique<HspPackager>(parameterMap, resultReceiver);
213 }
214
215 if (packager == nullptr || packager->PreProcess() != ERR_OK || packager->Process() != ERR_OK) {
216 return false;
217 }
218 return true;
219 }
220
221
ProcessJsonFiles(const std::string & tempPath,std::list<NormalizeVersion> & normalizeVersionList,const int32_t & versionCode,const std::string & versionName)222 bool VersionNormalize::ProcessJsonFiles(const std::string &tempPath, std::list<NormalizeVersion> &normalizeVersionList,
223 const int32_t &versionCode, const std::string &versionName)
224 {
225 NormalizeVersion normalizeVersion;
226 std::string moduleJsonPath = tempPath + Constants::LINUX_FILE_SEPARATOR + Constants::MODULE_JSON;
227 std::string configJsonPath = tempPath + Constants::LINUX_FILE_SEPARATOR + Constants::CONFIG_JSON;
228 std::string packInfoPath = tempPath + Constants::LINUX_FILE_SEPARATOR + Constants::PACK_INFO;
229
230 bool isModuleFileExists = fs::exists(moduleJsonPath);
231 bool isConfigFileExists = fs::exists(configJsonPath);
232 bool isPackInfoFileExists = fs::exists(packInfoPath);
233 if (isModuleFileExists == isConfigFileExists) {
234 LOGE("VersionNormalize failed, invalid hap structure.");
235 return false;
236 }
237
238 bool modifyJsonSuccess = false;
239 if (isModuleFileExists) {
240 modifyJsonSuccess = ModifyModuleJson(moduleJsonPath, normalizeVersion, versionCode, versionName);
241 } else {
242 modifyJsonSuccess = ModifyConfigJson(configJsonPath, normalizeVersion, versionCode, versionName);
243 }
244
245 if (!modifyJsonSuccess) {
246 normalizeVersionList.push_back(normalizeVersion);
247 return false;
248 }
249
250 if (isPackInfoFileExists) {
251 if (!ModifyPackInfo(packInfoPath, versionCode, versionName)) {
252 normalizeVersionList.push_back(normalizeVersion);
253 return false;
254 }
255 }
256
257 if (!VerifyModuleVersion(normalizeVersion, versionCode, versionName)) {
258 return false;
259 }
260 normalizeVersionList.push_back(normalizeVersion);
261 return true;
262 }
263
Process()264 int32_t VersionNormalize::Process()
265 {
266 std::string outPath = parameterMap_.at(Constants::PARAM_OUT_PATH);
267 std::string tempPath = outPath + Constants::LINUX_FILE_SEPARATOR + Constants::COMPRESSOR_VERSIONNORMALIZE_TEMP_DIR
268 + Utils::GenerateUUID();
269 int32_t versionCode = std::stoi(parameterMap_.at(Constants::PARAM_VERSION_CODE));
270 std::string versionName = parameterMap_.at(Constants::PARAM_VERSION_NAME);
271 std::list<NormalizeVersion> normalizeVersionList;
272
273 for (const std::string& path : hspOrhapList_) {
274 ZipUtils::Unzip(path, tempPath);
275 if (!ProcessJsonFiles(tempPath, normalizeVersionList, versionCode, versionName)) {
276 Utils::ForceRemoveDirectory(tempPath);
277 continue;
278 }
279 if (!CompressDirToHap(tempPath,
280 outPath + Constants::LINUX_FILE_SEPARATOR + fs::path(path).filename().string())) {
281 Utils::ForceRemoveDirectory(tempPath);
282 continue;
283 }
284 Utils::ForceRemoveDirectory(tempPath);
285 }
286
287 if (!JsonUtils::StrToFile(NormalizeVersionUtils::ArrayToString(normalizeVersionList), outPath +
288 Constants::LINUX_FILE_SEPARATOR + Constants::VERSION_RECORD)) {
289 LOGE("WriteVersionRecord failed.");
290 return ERR_INVALID_VALUE;
291 }
292 return ERR_OK;
293 }
294
PostProcess()295 int32_t VersionNormalize::PostProcess()
296 {
297 return ERR_OK;
298 }
299 } // namespace AppPackingTool
300 } // namespace OHOS