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 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
227 }
228
229 PreBundleProfile preBundleProfile;
230 return preBundleProfile.TransformTo(jsonBuf, scanInfos);
231 }
232
ParsePreUnInstallConfig(const std::string & configFile,std::set<std::string> & uninstallList) const233 ErrCode BundleParser::ParsePreUnInstallConfig(
234 const std::string &configFile,
235 std::set<std::string> &uninstallList) const
236 {
237 APP_LOGD("Parse PreUnInstallConfig from %{public}s", configFile.c_str());
238 nlohmann::json jsonBuf;
239 if (!ReadFileIntoJson(configFile, jsonBuf)) {
240 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
241 }
242
243 PreBundleProfile preBundleProfile;
244 return preBundleProfile.TransformTo(jsonBuf, uninstallList);
245 }
246
ParsePreInstallAbilityConfig(const std::string & configFile,std::set<PreBundleConfigInfo> & preBundleConfigInfos) const247 ErrCode BundleParser::ParsePreInstallAbilityConfig(
248 const std::string &configFile, std::set<PreBundleConfigInfo> &preBundleConfigInfos) const
249 {
250 APP_LOGD("Parse PreInstallAbilityConfig from %{public}s", configFile.c_str());
251 nlohmann::json jsonBuf;
252 if (!ReadFileIntoJson(configFile, jsonBuf)) {
253 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
254 }
255
256 PreBundleProfile preBundleProfile;
257 return preBundleProfile.TransformTo(jsonBuf, preBundleConfigInfos);
258 }
259
ParseDefaultPermission(const std::string & permissionFile,std::set<DefaultPermission> & defaultPermissions) const260 ErrCode BundleParser::ParseDefaultPermission(
261 const std::string &permissionFile, std::set<DefaultPermission> &defaultPermissions) const
262 {
263 APP_LOGD("Parse DefaultPermission from %{private}s", permissionFile.c_str());
264 nlohmann::json jsonBuf;
265 if (!ReadFileIntoJson(permissionFile, jsonBuf)) {
266 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
267 }
268
269 DefaultPermissionProfile profile;
270 return profile.TransformTo(jsonBuf, defaultPermissions);
271 }
272
ParseExtTypeConfig(const std::string & configFile,std::set<std::string> & extensionTypeList) const273 ErrCode BundleParser::ParseExtTypeConfig(
274 const std::string &configFile, std::set<std::string> &extensionTypeList) const
275 {
276 nlohmann::json jsonBuf;
277 if (!ReadFileIntoJson(configFile, jsonBuf)) {
278 return ERR_APPEXECFWK_PARSE_FILE_FAILED;
279 }
280
281 PreBundleProfile preBundleProfile;
282 return preBundleProfile.TransformJsonToExtensionTypeList(jsonBuf, extensionTypeList);
283 }
284
CheckRouterData(nlohmann::json data) const285 bool BundleParser::CheckRouterData(nlohmann::json data) const
286 {
287 if (data.find(ROUTER_MAP_DATA) == data.end()) {
288 APP_LOGW("data is not existed");
289 return false;
290 }
291 if (!data.at(ROUTER_MAP_DATA).is_object()) {
292 APP_LOGW("data is not a json object");
293 return false;
294 }
295 for (nlohmann::json::iterator kt = data.at(ROUTER_MAP_DATA).begin(); kt != data.at(ROUTER_MAP_DATA).end(); ++kt) {
296 // check every value is string
297 if (!kt.value().is_string()) {
298 APP_LOGW("Error: Value in data object for key %{public}s must be a string", kt.key().c_str());
299 return false;
300 }
301 }
302 return true;
303 }
304
ParseRouterArray(const std::string & jsonString,std::vector<RouterItem> & routerArray) const305 ErrCode BundleParser::ParseRouterArray(
306 const std::string &jsonString, std::vector<RouterItem> &routerArray) const
307 {
308 if (jsonString.empty()) {
309 APP_LOGE("jsonString is empty");
310 return ERR_APPEXECFWK_PARSE_NO_PROFILE;
311 }
312 APP_LOGD("Parse RouterItem from %{private}s", jsonString.c_str());
313 nlohmann::json jsonBuf = nlohmann::json::parse(jsonString, nullptr, false);
314 if (jsonBuf.is_discarded()) {
315 APP_LOGE("json file %{private}s discarded", jsonString.c_str());
316 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
317 }
318 if (jsonBuf.find(ROUTER_MAP) == jsonBuf.end()) {
319 APP_LOGE("routerMap no exist");
320 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
321 }
322 nlohmann::json routerJson = jsonBuf.at(ROUTER_MAP);
323 if (!routerJson.is_array()) {
324 APP_LOGE("json under routerMap is not a json array");
325 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
326 }
327
328 for (const auto &object : routerJson) {
329 if (!object.is_object()) {
330 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
331 }
332 RouterItem routerItem;
333 if (object.count(ROUTER_MAP_DATA) > 0 && !CheckRouterData(object)) {
334 APP_LOGW("check data type failed");
335 continue;
336 }
337 from_json(object, routerItem);
338 if (object.find(ROUTER_ITEM_KEY_CUSTOM_DATA) != object.end()) {
339 if (object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump().size() <= DATA_MAX_LENGTH) {
340 routerItem.customData = object[ROUTER_ITEM_KEY_CUSTOM_DATA].dump();
341 } else {
342 APP_LOGE("customData in routerMap profile is too long");
343 }
344 }
345 routerArray.emplace_back(routerItem);
346 }
347 return ERR_OK;
348 }
349
ParseNoDisablingList(const std::string & configPath,std::vector<std::string> & noDisablingList)350 ErrCode BundleParser::ParseNoDisablingList(const std::string &configPath, std::vector<std::string> &noDisablingList)
351 {
352 nlohmann::json object;
353 if (!ReadFileIntoJson(configPath, object)) {
354 return ERR_APPEXECFWK_INSTALL_FAILED_PROFILE_PARSE_FAIL;
355 }
356 if (!object.contains(NO_DISABLING_CONFIG_KEY) || !object.at(NO_DISABLING_CONFIG_KEY).is_array()) {
357 APP_LOGE("no disabling config not existed");
358 return ERR_APPEXECFWK_PARSE_PROFILE_PROP_TYPE_ERROR;
359 }
360 for (auto &item : object.at(NO_DISABLING_CONFIG_KEY).items()) {
361 const nlohmann::json& jsonObject = item.value();
362 if (jsonObject.contains(NO_DISABLING_KEY_BUNDLE_NAME) &&
363 jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).is_string()) {
364 std::string bundleName = jsonObject.at(NO_DISABLING_KEY_BUNDLE_NAME).get<std::string>();
365 noDisablingList.emplace_back(bundleName);
366 }
367 }
368 return ERR_OK;
369 }
370 } // namespace AppExecFwk
371 } // namespace OHOS
372