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 "default_permission_profile.h"
23 #include "module_profile.h"
24 #include "pre_bundle_profile.h"
25 #include "rpcid_decode/syscap_tool.h"
26 #include "securec.h"
27
28 namespace OHOS {
29 namespace AppExecFwk {
30 namespace {
31 const std::string INSTALL_ABILITY_CONFIGS = "install_ability_configs";
32 constexpr const char* BUNDLE_PACKFILE_NAME = "pack.info";
33 constexpr const char* SYSCAP_NAME = "rpcid.sc";
34 static const std::string ROUTER_MAP = "routerMap";
35 static const std::string ROUTER_MAP_DATA = "data";
36 static const std::string ROUTER_ITEM_KEY_CUSTOM_DATA = "customData";
37 static const size_t DATA_MAX_LENGTH = 4096;
38 const char* NO_DISABLING_CONFIG_KEY = "residentProcessInExtremeMemory";
39 const char* NO_DISABLING_KEY_BUNDLE_NAME = "bundleName";
40
ParseStr(const char * buf,const int itemLen,int totalLen,std::vector<std::string> & sysCaps)41 bool ParseStr(const char *buf, const int itemLen, int totalLen, std::vector<std::string> &sysCaps)
42 {
43 APP_LOGD("Parse rpcid output start, itemLen:%{public}d totalLen:%{public}d", itemLen, totalLen);
44 if (buf == nullptr || itemLen <= 0 || totalLen <= 0) {
45 APP_LOGE("param invalid");
46 return false;
47 }
48
49 int index = 0;
50 while (index + itemLen <= totalLen) {
51 char item[itemLen];
52 if (strncpy_s(item, sizeof(item), buf + index, itemLen) != 0) {
53 APP_LOGE("Parse rpcid failed due to strncpy_s error");
54 return false;
55 }
56
57 sysCaps.emplace_back((std::string)item, 0, itemLen);
58 index += itemLen;
59 }
60
61 return true;
62 }
63 } // namespace
64
ReadFileIntoJson(const std::string & filePath,nlohmann::json & jsonBuf)65 bool BundleParser::ReadFileIntoJson(const std::string &filePath, nlohmann::json &jsonBuf)
66 {
67 if (access(filePath.c_str(), F_OK) != 0) {
68 APP_LOGD("access file %{public}s failed, error: %{public}s", filePath.c_str(), strerror(errno));
69 return false;
70 }
71
72 std::fstream in;
73 char errBuf[256];
74 errBuf[0] = '\0';
75 in.open(filePath, std::ios_base::in);
76 if (!in.is_open()) {
77 strerror_r(errno, errBuf, sizeof(errBuf));
78 APP_LOGE("file open failed due to %{public}s, errno:%{public}d", errBuf, errno);
79 return false;
80 }
81
82 in.seekg(0, std::ios::end);
83 int64_t size = in.tellg();
84 if (size <= 0) {
85 APP_LOGE("file empty, errno:%{public}d", errno);
86 in.close();
87 return false;
88 }
89
90 in.seekg(0, std::ios::beg);
91 jsonBuf = nlohmann::json::parse(in, nullptr, false);
92 in.close();
93 if (jsonBuf.is_discarded()) {
94 APP_LOGE("bad profile file");
95 return false;
96 }
97
98 return true;
99 }
100
Parse(const std::string & pathName,InnerBundleInfo & innerBundleInfo) const101 ErrCode BundleParser::Parse(
102 const std::string &pathName,
103 InnerBundleInfo &innerBundleInfo) const
104 {
105 APP_LOGD("parse from %{private}s", pathName.c_str());
106 BundleExtractor bundleExtractor(pathName);
107 if (!bundleExtractor.Init()) {
108 APP_LOGE("bundle extractor init failed");
109 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
110 }
111
112 // to extract config.json
113 std::ostringstream outStream;
114 if (!bundleExtractor.ExtractProfile(outStream)) {
115 APP_LOGE("extract profile file failed");
116 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
117 }
118
119 if (bundleExtractor.IsNewVersion()) {
120 APP_LOGD("module.json transform to InnerBundleInfo");
121 innerBundleInfo.SetIsNewVersion(true);
122 ModuleProfile moduleProfile;
123 return moduleProfile.TransformTo(
124 outStream, bundleExtractor, innerBundleInfo);
125 }
126 APP_LOGD("config.json transform to InnerBundleInfo");
127 innerBundleInfo.SetIsNewVersion(false);
128 BundleProfile bundleProfile;
129 ErrCode ret = bundleProfile.TransformTo(
130 outStream, bundleExtractor, innerBundleInfo);
131 if (ret != ERR_OK) {
132 APP_LOGE("transform stream to innerBundleInfo failed %{public}d", ret);
133 return ret;
134 }
135 auto& abilityInfos = innerBundleInfo.FetchAbilityInfos();
136 for (auto& info : abilityInfos) {
137 info.second.isStageBasedModel = bundleExtractor.IsStageBasedModel(info.second.name);
138 auto iter = innerBundleInfo.FetchInnerModuleInfos().find(info.second.package);
139 if (iter != innerBundleInfo.FetchInnerModuleInfos().end()) {
140 iter->second.isStageBasedModel = info.second.isStageBasedModel;
141 }
142 }
143
144 return ERR_OK;
145 }
146
ParsePackInfo(const std::string & pathName,BundlePackInfo & bundlePackInfo) const147 ErrCode BundleParser::ParsePackInfo(const std::string &pathName, BundlePackInfo &bundlePackInfo) const
148 {
149 APP_LOGD("parse from %{private}s", pathName.c_str());
150 BundleExtractor bundleExtractor(pathName);
151 if (!bundleExtractor.Init()) {
152 APP_LOGE("bundle extractor init failed");
153 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
154 }
155
156 // to extract pack.info
157 if (!bundleExtractor.HasEntry(BUNDLE_PACKFILE_NAME)) {
158 APP_LOGW("cannot find pack.info in the hap file");
159 return ERR_OK;
160 }
161 std::ostringstream outStreamForPackInfo;
162 if (!bundleExtractor.ExtractPackFile(outStreamForPackInfo)) {
163 APP_LOGE("extract profile file failed");
164 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
165 }
166 BundleProfile bundleProfile;
167 ErrCode ret = bundleProfile.TransformTo(outStreamForPackInfo, bundlePackInfo);
168 if (ret != ERR_OK) {
169 APP_LOGE("transform stream to bundlePackinfo failed %{public}d", ret);
170 return ret;
171 }
172 return ERR_OK;
173 }
174
ParseSysCap(const std::string & pathName,std::vector<std::string> & sysCaps) const175 ErrCode BundleParser::ParseSysCap(const std::string &pathName, std::vector<std::string> &sysCaps) const
176 {
177 APP_LOGD("Parse sysCaps from %{private}s", pathName.c_str());
178 BundleExtractor bundleExtractor(pathName);
179 if (!bundleExtractor.Init()) {
180 APP_LOGE("Bundle extractor init failed");
181 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
182 }
183
184 if (!bundleExtractor.HasEntry(SYSCAP_NAME)) {
185 APP_LOGD("Rpcid.sc is not exist, and do not need verification sysCaps");
186 return ERR_OK;
187 }
188
189 std::stringstream rpcidStream;
190 if (!bundleExtractor.ExtractByName(SYSCAP_NAME, rpcidStream)) {
191 APP_LOGE("Extract rpcid file failed");
192 return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
193 }
194
195 int32_t rpcidLen = rpcidStream.tellp();
196 if (rpcidLen < 0) {
197 return ERR_APPEXECFWK_PARSE_UNEXPECTED;
198 }
199 char rpcidBuf[rpcidLen];
200 rpcidStream.read(rpcidBuf, rpcidLen);
201 uint32_t outLen;
202 char *outBuffer;
203 int result = RPCIDStreamDecodeToBuffer(rpcidBuf, rpcidLen, &outBuffer, &outLen);
204 if (result != 0) {
205 APP_LOGE("Decode syscaps failed");
206 return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
207 }
208
209 if (!ParseStr(outBuffer, SINGLE_SYSCAP_LENGTH, outLen, sysCaps)) {
210 APP_LOGE("Parse syscaps str failed");
211 free(outBuffer);
212 return ERR_APPEXECFWK_PARSE_RPCID_FAILED;
213 }
214
215 APP_LOGD("Parse sysCaps str success");
216 free(outBuffer);
217 return ERR_OK;
218 }
219
ParsePreInstallConfig(const std::string & configFile,std::set<PreScanInfo> & scanInfos) const220 ErrCode BundleParser::ParsePreInstallConfig(
221 const std::string &configFile, std::set<PreScanInfo> &scanInfos) const
222 {
223 APP_LOGD("Parse preInstallConfig from %{public}s", configFile.c_str());
224 nlohmann::json jsonBuf;
225 if (!ReadFileIntoJson(configFile, jsonBuf)) {
226 APP_LOGE_NOFUNC("Parse file %{public}s failed", configFile.c_str());
227 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
228 }
229
230 PreBundleProfile preBundleProfile;
231 return preBundleProfile.TransformTo(jsonBuf, scanInfos);
232 }
233
ParsePreUnInstallConfig(const std::string & configFile,std::set<std::string> & uninstallList) const234 ErrCode BundleParser::ParsePreUnInstallConfig(
235 const std::string &configFile,
236 std::set<std::string> &uninstallList) const
237 {
238 APP_LOGD("Parse PreUnInstallConfig from %{public}s", configFile.c_str());
239 nlohmann::json jsonBuf;
240 if (!ReadFileIntoJson(configFile, jsonBuf)) {
241 APP_LOGE_NOFUNC("Parse file %{public}s failed", configFile.c_str());
242 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
243 }
244
245 PreBundleProfile preBundleProfile;
246 return preBundleProfile.TransformTo(jsonBuf, uninstallList);
247 }
248
ParsePreInstallAbilityConfig(const std::string & configFile,std::set<PreBundleConfigInfo> & preBundleConfigInfos) const249 ErrCode BundleParser::ParsePreInstallAbilityConfig(
250 const std::string &configFile, std::set<PreBundleConfigInfo> &preBundleConfigInfos) const
251 {
252 APP_LOGD("Parse PreInstallAbilityConfig from %{public}s", configFile.c_str());
253 nlohmann::json jsonBuf;
254 if (!ReadFileIntoJson(configFile, jsonBuf)) {
255 APP_LOGE("Parse file %{public}s failed", configFile.c_str());
256 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
257 }
258
259 PreBundleProfile preBundleProfile;
260 return preBundleProfile.TransformTo(jsonBuf, preBundleConfigInfos);
261 }
262
ParseDefaultPermission(const std::string & permissionFile,std::set<DefaultPermission> & defaultPermissions) const263 ErrCode BundleParser::ParseDefaultPermission(
264 const std::string &permissionFile, std::set<DefaultPermission> &defaultPermissions) const
265 {
266 APP_LOGD("Parse DefaultPermission from %{private}s", permissionFile.c_str());
267 nlohmann::json jsonBuf;
268 if (!ReadFileIntoJson(permissionFile, jsonBuf)) {
269 APP_LOGE_NOFUNC("Parse file %{public}s failed", permissionFile.c_str());
270 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
271 }
272
273 DefaultPermissionProfile profile;
274 return profile.TransformTo(jsonBuf, defaultPermissions);
275 }
276
ParseExtTypeConfig(const std::string & configFile,std::set<std::string> & extensionTypeList) const277 ErrCode BundleParser::ParseExtTypeConfig(
278 const std::string &configFile, std::set<std::string> &extensionTypeList) const
279 {
280 nlohmann::json jsonBuf;
281 if (!ReadFileIntoJson(configFile, jsonBuf)) {
282 APP_LOGE_NOFUNC("Parse file %{public}s failed", configFile.c_str());
283 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
284 }
285
286 PreBundleProfile preBundleProfile;
287 return preBundleProfile.TransformJsonToExtensionTypeList(jsonBuf, extensionTypeList);
288 }
289
CheckRouterData(nlohmann::json data) const290 bool BundleParser::CheckRouterData(nlohmann::json data) const
291 {
292 if (data.find(ROUTER_MAP_DATA) == data.end()) {
293 APP_LOGW("data is not existed");
294 return false;
295 }
296 if (!data.at(ROUTER_MAP_DATA).is_object()) {
297 APP_LOGW("data is not a json object");
298 return false;
299 }
300 for (nlohmann::json::iterator kt = data.at(ROUTER_MAP_DATA).begin(); kt != data.at(ROUTER_MAP_DATA).end(); ++kt) {
301 // check every value is string
302 if (!kt.value().is_string()) {
303 APP_LOGW("Error: Value in data object for key %{public}s must be a string", kt.key().c_str());
304 return false;
305 }
306 }
307 return true;
308 }
309
ParseRouterArray(const std::string & jsonString,std::vector<RouterItem> & routerArray) const310 ErrCode BundleParser::ParseRouterArray(
311 const std::string &jsonString, std::vector<RouterItem> &routerArray) const
312 {
313 if (jsonString.empty()) {
314 APP_LOGE("jsonString is empty");
315 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
316 }
317 APP_LOGD("Parse RouterItem from %{private}s", jsonString.c_str());
318 nlohmann::json jsonBuf = nlohmann::json::parse(jsonString, nullptr, false);
319 if (jsonBuf.is_discarded()) {
320 APP_LOGE("json file %{private}s discarded", jsonString.c_str());
321 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
322 }
323 if (jsonBuf.find(ROUTER_MAP) == jsonBuf.end()) {
324 APP_LOGE("routerMap no exist");
325 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
326 }
327 nlohmann::json routerJson = jsonBuf.at(ROUTER_MAP);
328 if (!routerJson.is_array()) {
329 APP_LOGE("json under routerMap is not a json array");
330 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
331 }
332
333 for (const auto &object : routerJson) {
334 if (!object.is_object()) {
335 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
336 }
337 RouterItem routerItem;
338 if (object.count(ROUTER_MAP_DATA) > 0 && !CheckRouterData(object)) {
339 APP_LOGW("check data type failed");
340 continue;
341 }
342 from_json(object, routerItem);
343 if (object.find(ROUTER_ITEM_KEY_CUSTOM_DATA) != object.end()) {
344 if (object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump().size() <= DATA_MAX_LENGTH) {
345 routerItem.customData = object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump();
346 } else {
347 APP_LOGE("customData in routerMap profile is too long");
348 }
349 }
350 routerArray.emplace_back(routerItem);
351 }
352 return ERR_OK;
353 }
354
ParseNoDisablingList(const std::string & configPath,std::vector<std::string> & noDisablingList)355 ErrCode BundleParser::ParseNoDisablingList(const std::string &configPath, std::vector<std::string> &noDisablingList)
356 {
357 nlohmann::json object;
358 if (!ReadFileIntoJson(configPath, object)) {
359 APP_LOGI("Parse file %{public}s failed", configPath.c_str());
360 return ERR_APPEXECFWK_INSTALL_FAILED_PROFILE_PARSE_FAIL;
361 }
362 if (!object.contains(NO_DISABLING_CONFIG_KEY) || !object.at(NO_DISABLING_CONFIG_KEY).is_array()) {
363 APP_LOGE("no disabling config not existed");
364 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
365 }
366 for (auto &item : object.at(NO_DISABLING_CONFIG_KEY).items()) {
367 const nlohmann::json& jsonObject = item.value();
368 if (jsonObject.contains(NO_DISABLING_KEY_BUNDLE_NAME) &&
369 jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).is_string()) {
370 std::string bundleName = jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).get<std::string>();
371 noDisablingList.emplace_back(bundleName);
372 }
373 }
374 return ERR_OK;
375 }
376 } // namespace AppExecFwk
377 } // namespace OHOS
378