• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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