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_LOGI("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) const236 ErrCode BundleParser::ParsePreAppListConfig(const std::string &configFile, std::set<PreScanInfo> &scanAppInfos) const
237 {
238 APP_LOGD("parse preAppListInstallConfig from %{public}s", configFile.c_str());
239 nlohmann::json jsonBuf;
240 if (!ReadFileIntoJson(configFile, jsonBuf)) {
241 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
242 }
243
244 PreBundleProfile preBundleProfile;
245 ErrCode ret = preBundleProfile.TransformToAppList(jsonBuf, scanAppInfos);
246 if (ret != ERR_OK) {
247 APP_LOGE_NOFUNC("set parameter BMS_DATA_PRELOAD false");
248 OHOS::system::SetParameter(ServiceConstants::BMS_DATA_PRELOAD, "false");
249 }
250 return ret;
251 }
252
ParsePreUnInstallConfig(const std::string & configFile,std::set<std::string> & uninstallList) const253 ErrCode BundleParser::ParsePreUnInstallConfig(
254 const std::string &configFile,
255 std::set<std::string> &uninstallList) const
256 {
257 APP_LOGD("Parse PreUnInstallConfig 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.TransformTo(jsonBuf, uninstallList);
265 }
266
ParsePreInstallAbilityConfig(const std::string & configFile,std::set<PreBundleConfigInfo> & preBundleConfigInfos) const267 ErrCode BundleParser::ParsePreInstallAbilityConfig(
268 const std::string &configFile, std::set<PreBundleConfigInfo> &preBundleConfigInfos) const
269 {
270 APP_LOGD("Parse PreInstallAbilityConfig from %{public}s", configFile.c_str());
271 nlohmann::json jsonBuf;
272 if (!ReadFileIntoJson(configFile, jsonBuf)) {
273 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
274 }
275
276 PreBundleProfile preBundleProfile;
277 return preBundleProfile.TransformTo(jsonBuf, preBundleConfigInfos);
278 }
279
ParseDefaultPermission(const std::string & permissionFile,std::set<DefaultPermission> & defaultPermissions) const280 ErrCode BundleParser::ParseDefaultPermission(
281 const std::string &permissionFile, std::set<DefaultPermission> &defaultPermissions) const
282 {
283 APP_LOGD("Parse DefaultPermission from %{private}s", permissionFile.c_str());
284 nlohmann::json jsonBuf;
285 if (!ReadFileIntoJson(permissionFile, jsonBuf)) {
286 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
287 }
288
289 DefaultPermissionProfile profile;
290 return profile.TransformTo(jsonBuf, defaultPermissions);
291 }
292
ParseAclExtendedMap(const std::string & appServiceCapabilities)293 std::map<std::string, std::string> BundleParser::ParseAclExtendedMap(const std::string &appServiceCapabilities)
294 {
295 std::map<std::string, std::string> aclExtendedMap;
296 if (appServiceCapabilities.empty()) {
297 APP_LOGD("appServiceCapabilities is empty");
298 return aclExtendedMap;
299 }
300 APP_LOGI("ParseAclExtendedMap from %{private}s", appServiceCapabilities.c_str());
301 nlohmann::json jsonBuf = nlohmann::json::parse(appServiceCapabilities, nullptr, false);
302 if (jsonBuf.is_discarded()) {
303 APP_LOGE("json file discarded");
304 return aclExtendedMap;
305 }
306 if (!jsonBuf.is_object()) {
307 APP_LOGE("jsonBuf is not object");
308 return aclExtendedMap;
309 }
310 for (const auto& [key, value] : jsonBuf.items()) {
311 aclExtendedMap[key] = value.is_string() ? value.get<std::string>() : value.dump();
312 }
313 return aclExtendedMap;
314 }
315
ParseExtTypeConfig(const std::string & configFile,std::set<std::string> & extensionTypeList) const316 ErrCode BundleParser::ParseExtTypeConfig(
317 const std::string &configFile, std::set<std::string> &extensionTypeList) const
318 {
319 nlohmann::json jsonBuf;
320 if (!ReadFileIntoJson(configFile, jsonBuf)) {
321 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
322 }
323
324 PreBundleProfile preBundleProfile;
325 return preBundleProfile.TransformJsonToExtensionTypeList(jsonBuf, extensionTypeList);
326 }
327
CheckRouterData(nlohmann::json data) const328 bool BundleParser::CheckRouterData(nlohmann::json data) const
329 {
330 if (data.find(ROUTER_MAP_DATA) == data.end()) {
331 APP_LOGW("data is not existed");
332 return false;
333 }
334 if (!data.at(ROUTER_MAP_DATA).is_object()) {
335 APP_LOGW("data is not a json object");
336 return false;
337 }
338 for (nlohmann::json::iterator kt = data.at(ROUTER_MAP_DATA).begin(); kt != data.at(ROUTER_MAP_DATA).end(); ++kt) {
339 // check every value is string
340 if (!kt.value().is_string()) {
341 APP_LOGW("Error: Value in data object for key %{public}s must be a string", kt.key().c_str());
342 return false;
343 }
344 }
345 return true;
346 }
347
ParseRouterArray(const std::string & jsonString,std::vector<RouterItem> & routerArray) const348 ErrCode BundleParser::ParseRouterArray(
349 const std::string &jsonString, std::vector<RouterItem> &routerArray) const
350 {
351 if (jsonString.empty()) {
352 APP_LOGE("jsonString is empty");
353 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
354 }
355 APP_LOGD("Parse RouterItem from %{private}s", jsonString.c_str());
356 nlohmann::json jsonBuf = nlohmann::json::parse(jsonString, nullptr, false);
357 if (jsonBuf.is_discarded()) {
358 APP_LOGE("json file %{private}s discarded", jsonString.c_str());
359 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
360 }
361 if (jsonBuf.find(ROUTER_MAP) == jsonBuf.end()) {
362 APP_LOGE("routerMap no exist");
363 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
364 }
365 nlohmann::json routerJson = jsonBuf.at(ROUTER_MAP);
366 if (!routerJson.is_array()) {
367 APP_LOGE("json under routerMap is not a json array");
368 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
369 }
370
371 for (const auto &object : routerJson) {
372 if (!object.is_object()) {
373 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
374 }
375 RouterItem routerItem;
376 if (object.count(ROUTER_MAP_DATA) > 0 && !CheckRouterData(object)) {
377 APP_LOGW("check data type failed");
378 continue;
379 }
380 from_json(object, routerItem);
381 if (object.find(ROUTER_ITEM_KEY_CUSTOM_DATA) != object.end()) {
382 if (object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump().size() <= DATA_MAX_LENGTH) {
383 routerItem.customData = object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump();
384 } else {
385 APP_LOGE("customData in routerMap profile is too long");
386 }
387 }
388 routerArray.emplace_back(routerItem);
389 }
390 return ERR_OK;
391 }
392
ParseNoDisablingList(const std::string & configPath,std::vector<std::string> & noDisablingList)393 ErrCode BundleParser::ParseNoDisablingList(const std::string &configPath, std::vector<std::string> &noDisablingList)
394 {
395 nlohmann::json object;
396 if (!ReadFileIntoJson(configPath, object)) {
397 return ERR_APPEXECFWK_INSTALL_FAILED_PROFILE_PARSE_FAIL;
398 }
399 if (!object.contains(NO_DISABLING_CONFIG_KEY) || !object.at(NO_DISABLING_CONFIG_KEY).is_array()) {
400 APP_LOGE("no disabling config not existed");
401 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
402 }
403 for (auto &item : object.at(NO_DISABLING_CONFIG_KEY).items()) {
404 const nlohmann::json& jsonObject = item.value();
405 if (jsonObject.contains(NO_DISABLING_KEY_BUNDLE_NAME) &&
406 jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).is_string()) {
407 std::string bundleName = jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).get<std::string>();
408 noDisablingList.emplace_back(bundleName);
409 }
410 }
411 return ERR_OK;
412 }
413 } // namespace AppExecFwk
414 } // namespace OHOS
415