1 /*
2 * Copyright (c) 2021-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 "bundle_parser.h"
17
18 #include <fstream>
19 #include <sstream>
20
21 #include "bundle_profile.h"
22 #include "bundle_service_constants.h"
23 #include "default_permission_profile.h"
24 #include "module_profile.h"
25 #include "parameter.h"
26 #include "parameters.h"
27 #include "pre_bundle_profile.h"
28 #include "rpcid_decode/syscap_tool.h"
29 #include "securec.h"
30
31 namespace OHOS {
32 namespace AppExecFwk {
33 namespace {
34 constexpr const char* BUNDLE_PACKFILE_NAME = "pack.info";
35 constexpr const char* SYSCAP_NAME = "rpcid.sc";
36 static constexpr const char* ROUTER_MAP = "routerMap";
37 static constexpr const char* ROUTER_MAP_DATA = "data";
38 static constexpr const char* ROUTER_ITEM_KEY_CUSTOM_DATA = "customData";
39 static constexpr const uint16_t DATA_MAX_LENGTH = 4096;
40 constexpr const char* NO_DISABLING_CONFIG_KEY = "residentProcessInExtremeMemory";
41 constexpr const char* NO_DISABLING_KEY_BUNDLE_NAME = "bundleName";
42
ParseStr(const char * buf,const int itemLen,int totalLen,std::vector<std::string> & sysCaps)43 bool ParseStr(const char *buf, const int itemLen, int totalLen, std::vector<std::string> &sysCaps)
44 {
45 APP_LOGD("Parse rpcid output start, itemLen:%{public}d totalLen:%{public}d", itemLen, totalLen);
46 if (buf == nullptr || itemLen <= 0 || totalLen <= 0) {
47 APP_LOGE("param invalid");
48 return false;
49 }
50
51 int index = 0;
52 while (index + itemLen <= totalLen) {
53 char item[itemLen + 1];
54 if (strncpy_s(item, sizeof(item), buf + index, itemLen) != 0) {
55 APP_LOGE("Parse rpcid failed due to strncpy_s error");
56 return false;
57 }
58
59 item[itemLen] = '\0';
60 sysCaps.emplace_back(std::string(item));
61 index += itemLen;
62 }
63
64 return true;
65 }
66 } // namespace
67
ReadFileIntoJson(const std::string & filePath,nlohmann::json & jsonBuf)68 bool BundleParser::ReadFileIntoJson(const std::string &filePath, nlohmann::json &jsonBuf)
69 {
70 if (access(filePath.c_str(), F_OK) != 0) {
71 APP_LOGW_NOFUNC("access file %{public}s failed, error: %{public}s", filePath.c_str(), strerror(errno));
72 return false;
73 }
74
75 std::fstream in;
76 char errBuf[256];
77 errBuf[0] = '\0';
78 in.open(filePath, std::ios_base::in);
79 if (!in.is_open()) {
80 strerror_r(errno, errBuf, sizeof(errBuf));
81 APP_LOGE_NOFUNC("file open failed due to %{public}s, errno:%{public}d", errBuf, errno);
82 return false;
83 }
84
85 in.seekg(0, std::ios::end);
86 int64_t size = in.tellg();
87 if (size <= 0) {
88 APP_LOGE_NOFUNC("file %{public}s empty, errno:%{public}d", filePath.c_str(), errno);
89 in.close();
90 return false;
91 }
92
93 in.seekg(0, std::ios::beg);
94 jsonBuf = nlohmann::json::parse(in, nullptr, false);
95 in.close();
96 if (jsonBuf.is_discarded()) {
97 APP_LOGE_NOFUNC("bad profile file %{public}s ", filePath.c_str());
98 return false;
99 }
100
101 return true;
102 }
103
Parse(const std::string & pathName,InnerBundleInfo & innerBundleInfo) const104 ErrCode BundleParser::Parse(
105 const std::string &pathName,
106 InnerBundleInfo &innerBundleInfo) const
107 {
108 APP_LOGD("parse from %{private}s", pathName.c_str());
109 BundleExtractor bundleExtractor(pathName);
110 if (!bundleExtractor.Init()) {
111 APP_LOGE("bundle extractor init failed");
112 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
113 }
114
115 // to extract config.json
116 std::ostringstream outStream;
117 if (!bundleExtractor.ExtractProfile(outStream)) {
118 APP_LOGE("extract profile file failed");
119 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
120 }
121
122 if (bundleExtractor.IsNewVersion()) {
123 APP_LOGD("module.json transform to InnerBundleInfo");
124 innerBundleInfo.SetIsNewVersion(true);
125 ModuleProfile moduleProfile;
126 return moduleProfile.TransformTo(
127 outStream, bundleExtractor, innerBundleInfo);
128 }
129 APP_LOGD("config.json transform to InnerBundleInfo");
130 innerBundleInfo.SetIsNewVersion(false);
131 BundleProfile bundleProfile;
132 ErrCode ret = bundleProfile.TransformTo(
133 outStream, bundleExtractor, innerBundleInfo);
134 if (ret != ERR_OK) {
135 APP_LOGE("transform stream to innerBundleInfo failed %{public}d", ret);
136 return ret;
137 }
138 auto& abilityInfos = innerBundleInfo.FetchAbilityInfos();
139 for (auto& info : abilityInfos) {
140 info.second.isStageBasedModel = bundleExtractor.IsStageBasedModel(info.second.name);
141 auto iter = innerBundleInfo.FetchInnerModuleInfos().find(info.second.package);
142 if (iter != innerBundleInfo.FetchInnerModuleInfos().end()) {
143 iter->second.isStageBasedModel = info.second.isStageBasedModel;
144 }
145 }
146
147 return ERR_OK;
148 }
149
ParsePackInfo(const std::string & pathName,BundlePackInfo & bundlePackInfo) const150 ErrCode BundleParser::ParsePackInfo(const std::string &pathName, BundlePackInfo &bundlePackInfo) const
151 {
152 APP_LOGD("parse from %{private}s", pathName.c_str());
153 BundleExtractor bundleExtractor(pathName);
154 if (!bundleExtractor.Init()) {
155 APP_LOGE("bundle extractor init failed");
156 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
157 }
158
159 // to extract pack.info
160 if (!bundleExtractor.HasEntry(BUNDLE_PACKFILE_NAME)) {
161 APP_LOGW("cannot find pack.info in the hap file");
162 return ERR_OK;
163 }
164 std::ostringstream outStreamForPackInfo;
165 if (!bundleExtractor.ExtractPackFile(outStreamForPackInfo)) {
166 APP_LOGE("extract profile file failed");
167 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
168 }
169 BundleProfile bundleProfile;
170 ErrCode ret = bundleProfile.TransformTo(outStreamForPackInfo, bundlePackInfo);
171 if (ret != ERR_OK) {
172 APP_LOGE("transform stream to bundlePackinfo failed %{public}d", ret);
173 return ret;
174 }
175 return ERR_OK;
176 }
177
ParseSysCap(const std::string & pathName,std::vector<std::string> & sysCaps) const178 ErrCode BundleParser::ParseSysCap(const std::string &pathName, std::vector<std::string> &sysCaps) const
179 {
180 APP_LOGD("Parse sysCaps from %{private}s", pathName.c_str());
181 BundleExtractor bundleExtractor(pathName);
182 if (!bundleExtractor.Init()) {
183 APP_LOGE("Bundle extractor init failed");
184 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
185 }
186
187 if (!bundleExtractor.HasEntry(SYSCAP_NAME)) {
188 APP_LOGD("Rpcid.sc is not exist, and do not need verification sysCaps");
189 return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
190 }
191
192 std::stringstream rpcidStream;
193 if (!bundleExtractor.ExtractByName(SYSCAP_NAME, rpcidStream)) {
194 APP_LOGE("Extract rpcid file failed");
195 return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
196 }
197
198 int32_t rpcidLen = rpcidStream.tellp();
199 if (rpcidLen < 0) {
200 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
201 }
202 char rpcidBuf[rpcidLen];
203 rpcidStream.read(rpcidBuf, rpcidLen);
204 uint32_t outLen;
205 char *outBuffer;
206 int result = RPCIDStreamDecodeToBuffer(rpcidBuf, rpcidLen, &outBuffer, &outLen);
207 if (result != 0) {
208 APP_LOGE("Decode syscaps failed");
209 return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
210 }
211
212 if (!ParseStr(outBuffer, SINGLE_SYSCAP_LENGTH, outLen, sysCaps)) {
213 APP_LOGE("Parse syscaps str failed");
214 free(outBuffer);
215 return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
216 }
217
218 APP_LOGD("Parse sysCaps str success");
219 free(outBuffer);
220 return ERR_OK;
221 }
222
ParsePreInstallConfig(const std::string & configFile,std::set<PreScanInfo> & scanInfos) const223 ErrCode BundleParser::ParsePreInstallConfig(
224 const std::string &configFile, std::set<PreScanInfo> &scanInfos) const
225 {
226 APP_LOGD("Parse preInstallConfig from %{public}s", configFile.c_str());
227 nlohmann::json jsonBuf;
228 if (!ReadFileIntoJson(configFile, jsonBuf)) {
229 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
230 }
231
232 PreBundleProfile preBundleProfile;
233 return preBundleProfile.TransformTo(jsonBuf, scanInfos);
234 }
235
ParsePreAppListConfig(const std::string & configFile,std::set<PreScanInfo> & scanAppInfos,std::set<PreScanInfo> & scanDemandInfos) const236 ErrCode BundleParser::ParsePreAppListConfig(const std::string &configFile, std::set<PreScanInfo> &scanAppInfos,
237 std::set<PreScanInfo> &scanDemandInfos) const
238 {
239 APP_LOGD("parse preAppListInstallConfig from %{public}s", configFile.c_str());
240 nlohmann::json jsonBuf;
241 if (!ReadFileIntoJson(configFile, jsonBuf)) {
242 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
243 }
244
245 PreBundleProfile preBundleProfile;
246 ErrCode ret = preBundleProfile.TransformToAppList(jsonBuf, scanAppInfos, scanDemandInfos);
247 if (ret != ERR_OK) {
248 APP_LOGE_NOFUNC("set parameter BMS_DATA_PRELOAD false");
249 OHOS::system::SetParameter(ServiceConstants::BMS_DATA_PRELOAD, "false");
250 }
251 return ret;
252 }
253
ParseDemandInstallConfig(const std::string & configFile,std::set<PreScanInfo> & scanInfos) const254 ErrCode BundleParser::ParseDemandInstallConfig(
255 const std::string &configFile, std::set<PreScanInfo> &scanInfos) const
256 {
257 APP_LOGD("Parse onDemandInstallConfig from %{public}s", configFile.c_str());
258 nlohmann::json jsonBuf;
259 if (!ReadFileIntoJson(configFile, jsonBuf)) {
260 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
261 }
262
263 PreBundleProfile preBundleProfile;
264 return preBundleProfile.TransformToDemandList(jsonBuf, scanInfos);
265 }
266
ParsePreUnInstallConfig(const std::string & configFile,std::set<std::string> & uninstallList) const267 ErrCode BundleParser::ParsePreUnInstallConfig(
268 const std::string &configFile,
269 std::set<std::string> &uninstallList) const
270 {
271 APP_LOGD("Parse PreUnInstallConfig from %{public}s", configFile.c_str());
272 nlohmann::json jsonBuf;
273 if (!ReadFileIntoJson(configFile, jsonBuf)) {
274 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
275 }
276
277 PreBundleProfile preBundleProfile;
278 return preBundleProfile.TransformTo(jsonBuf, uninstallList);
279 }
280
ParsePreInstallAbilityConfig(const std::string & configFile,std::set<PreBundleConfigInfo> & preBundleConfigInfos) const281 ErrCode BundleParser::ParsePreInstallAbilityConfig(
282 const std::string &configFile, std::set<PreBundleConfigInfo> &preBundleConfigInfos) const
283 {
284 APP_LOGD("Parse PreInstallAbilityConfig from %{public}s", configFile.c_str());
285 nlohmann::json jsonBuf;
286 if (!ReadFileIntoJson(configFile, jsonBuf)) {
287 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
288 }
289
290 PreBundleProfile preBundleProfile;
291 return preBundleProfile.TransformTo(jsonBuf, preBundleConfigInfos);
292 }
293
ParseDefaultPermission(const std::string & permissionFile,std::set<DefaultPermission> & defaultPermissions) const294 ErrCode BundleParser::ParseDefaultPermission(
295 const std::string &permissionFile, std::set<DefaultPermission> &defaultPermissions) const
296 {
297 APP_LOGD("Parse DefaultPermission from %{private}s", permissionFile.c_str());
298 nlohmann::json jsonBuf;
299 if (!ReadFileIntoJson(permissionFile, jsonBuf)) {
300 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
301 }
302
303 DefaultPermissionProfile profile;
304 return profile.TransformTo(jsonBuf, defaultPermissions);
305 }
306
ParseAclExtendedMap(const std::string & appServiceCapabilities)307 std::map<std::string, std::string> BundleParser::ParseAclExtendedMap(const std::string &appServiceCapabilities)
308 {
309 std::map<std::string, std::string> aclExtendedMap;
310 if (appServiceCapabilities.empty()) {
311 APP_LOGD("appServiceCapabilities is empty");
312 return aclExtendedMap;
313 }
314 APP_LOGI("ParseAclExtendedMap from %{private}s", appServiceCapabilities.c_str());
315 nlohmann::json jsonBuf = nlohmann::json::parse(appServiceCapabilities, nullptr, false);
316 if (jsonBuf.is_discarded()) {
317 APP_LOGE("json file discarded");
318 return aclExtendedMap;
319 }
320 if (!jsonBuf.is_object()) {
321 APP_LOGE("jsonBuf is not object");
322 return aclExtendedMap;
323 }
324 for (const auto& [key, value] : jsonBuf.items()) {
325 aclExtendedMap[key] = value.is_string() ? value.get<std::string>() : value.dump();
326 }
327 return aclExtendedMap;
328 }
329
ParseExtTypeConfig(const std::string & configFile,std::set<std::string> & extensionTypeList) const330 ErrCode BundleParser::ParseExtTypeConfig(
331 const std::string &configFile, std::set<std::string> &extensionTypeList) const
332 {
333 nlohmann::json jsonBuf;
334 if (!ReadFileIntoJson(configFile, jsonBuf)) {
335 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
336 }
337
338 PreBundleProfile preBundleProfile;
339 return preBundleProfile.TransformJsonToExtensionTypeList(jsonBuf, extensionTypeList);
340 }
341
CheckRouterData(nlohmann::json data) const342 bool BundleParser::CheckRouterData(nlohmann::json data) const
343 {
344 if (data.find(ROUTER_MAP_DATA) == data.end()) {
345 APP_LOGW("data is not existed");
346 return false;
347 }
348 if (!data.at(ROUTER_MAP_DATA).is_object()) {
349 APP_LOGW("data is not a json object");
350 return false;
351 }
352 for (nlohmann::json::iterator kt = data.at(ROUTER_MAP_DATA).begin(); kt != data.at(ROUTER_MAP_DATA).end(); ++kt) {
353 // check every value is string
354 if (!kt.value().is_string()) {
355 APP_LOGW("Error: Value in data object for key %{public}s must be a string", kt.key().c_str());
356 return false;
357 }
358 }
359 return true;
360 }
361
ParseRouterArray(const std::string & jsonString,std::vector<RouterItem> & routerArray) const362 ErrCode BundleParser::ParseRouterArray(
363 const std::string &jsonString, std::vector<RouterItem> &routerArray) const
364 {
365 if (jsonString.empty()) {
366 APP_LOGE("jsonString is empty");
367 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
368 }
369 APP_LOGD("Parse RouterItem from %{private}s", jsonString.c_str());
370 nlohmann::json jsonBuf = nlohmann::json::parse(jsonString, nullptr, false);
371 if (jsonBuf.is_discarded()) {
372 APP_LOGE("json file %{private}s discarded", jsonString.c_str());
373 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
374 }
375 if (jsonBuf.find(ROUTER_MAP) == jsonBuf.end()) {
376 APP_LOGE("routerMap no exist");
377 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
378 }
379 nlohmann::json routerJson = jsonBuf.at(ROUTER_MAP);
380 if (!routerJson.is_array()) {
381 APP_LOGE("json under routerMap is not a json array");
382 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
383 }
384
385 for (const auto &object : routerJson) {
386 if (!object.is_object()) {
387 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
388 }
389 RouterItem routerItem;
390 if (object.count(ROUTER_MAP_DATA) > 0 && !CheckRouterData(object)) {
391 APP_LOGW("check data type failed");
392 continue;
393 }
394 from_json(object, routerItem);
395 if (object.find(ROUTER_ITEM_KEY_CUSTOM_DATA) != object.end()) {
396 if (object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump().size() <= DATA_MAX_LENGTH) {
397 routerItem.customData = object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump();
398 } else {
399 APP_LOGE("customData in routerMap profile is too long");
400 }
401 }
402 routerArray.emplace_back(routerItem);
403 }
404 return ERR_OK;
405 }
406
ParseNoDisablingList(const std::string & configPath,std::vector<std::string> & noDisablingList)407 ErrCode BundleParser::ParseNoDisablingList(const std::string &configPath, std::vector<std::string> &noDisablingList)
408 {
409 nlohmann::json object;
410 if (!ReadFileIntoJson(configPath, object)) {
411 return ERR_APPEXECFWK_INSTALL_FAILED_PROFILE_PARSE_FAIL;
412 }
413 if (!object.contains(NO_DISABLING_CONFIG_KEY) || !object.at(NO_DISABLING_CONFIG_KEY).is_array()) {
414 APP_LOGE("no disabling config not existed");
415 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
416 }
417 for (auto &item : object.at(NO_DISABLING_CONFIG_KEY).items()) {
418 const nlohmann::json& jsonObject = item.value();
419 if (jsonObject.contains(NO_DISABLING_KEY_BUNDLE_NAME) &&
420 jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).is_string()) {
421 std::string bundleName = jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).get<std::string>();
422 noDisablingList.emplace_back(bundleName);
423 }
424 }
425 return ERR_OK;
426 }
427
ParseArkStartupCacheConfig(const std::string & configFile,std::unordered_set<std::string> & bundleNames)428 ErrCode BundleParser::ParseArkStartupCacheConfig(
429 const std::string &configFile,
430 std::unordered_set<std::string> &bundleNames)
431 {
432 APP_LOGD("Parse ParseArkStartupCacheConfig from %{public}s", configFile.c_str());
433 nlohmann::json jsonBuf;
434 if (!ReadFileIntoJson(configFile, jsonBuf)) {
435 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
436 }
437 PreBundleProfile preBundleProfile;
438 return preBundleProfile.TransToArkStartupCacheList(jsonBuf, bundleNames);
439 }
440
ParseTestRunner(const std::string & hapPath,ModuleTestRunner & testRunner) const441 ErrCode BundleParser::ParseTestRunner(
442 const std::string &hapPath,
443 ModuleTestRunner &testRunner) const
444 {
445 APP_LOGD("parse from %{private}s", hapPath.c_str());
446 BundleExtractor bundleExtractor(hapPath);
447 if (!bundleExtractor.Init()) {
448 APP_LOGE("bundle extractor init failed");
449 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
450 }
451
452 // to extract module.json
453 std::ostringstream outStream;
454 if (!bundleExtractor.ExtractModuleProfile(outStream)) {
455 APP_LOGE("extract profile file failed");
456 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
457 }
458 ModuleProfile moduleProfile;
459 return moduleProfile.TransformToTestRunner(outStream, testRunner);
460 }
461 } // namespace AppExecFwk
462 } // namespace OHOS
463