1 /*
2 * Copyright (c) 2025 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 "adapter/ohos/capability/feature_config/config_xml_parser_base.h"
17
18 #include <array>
19
20 #include "adapter/ohos/capability/feature_config/feature_param_manager.h"
21 #include "base/log/log.h"
22
23 namespace OHOS::Ace {
24
25 enum ParseXmlNodeIndex : uint32_t {
26 PARSE_XML_UNDEFINED = 0,
27 PARSE_XML_PERFORMANCE_OPT_CONFIG,
28 PARSE_XML_BUNDLE_NAME,
29 PARSE_XML_FEATURE,
30 PARSE_XML_MAX_SIZE,
31 };
32
33 namespace {
34 static const std::array<std::string, PARSE_XML_MAX_SIZE> XML_NODE_NAME_ARRAY = {
35 "undefine", // PARSE_XML_UNDEFINED
36 "PerformanceOptConfig", // PARSE_XML_PERFORMANCE_OPT_CONFIG
37 "bundleName", // PARSE_XML_BUNDLE_NAME
38 "feature", // PARSE_XML_FEATURE
39 };
40
41 static const std::array<std::string, 1> SYS_PATH = { "/etc" };
42 static constexpr char CONFIG_PATH[] = "/arkui/arkui_async_build_config.xml";
43 } // namespace
44
~ConfigXMLParserBase()45 ConfigXMLParserBase::~ConfigXMLParserBase()
46 {
47 Destroy();
48 }
49
Destroy()50 void ConfigXMLParserBase::Destroy()
51 {
52 if (xmlSysDocument_ != nullptr) {
53 xmlFreeDoc(xmlSysDocument_);
54 xmlSysDocument_ = nullptr;
55 }
56 }
57
LoadPerformanceConfigXML()58 ParseErrCode ConfigXMLParserBase::LoadPerformanceConfigXML()
59 {
60 for (const std::string& configRootPath : SYS_PATH) {
61 std::string graphicFilePath = configRootPath + CONFIG_PATH;
62 xmlSysDocument_ = xmlReadFile(graphicFilePath.c_str(), nullptr, 0);
63 if (xmlSysDocument_ != nullptr) {
64 LOGD("ConfigXMLParserBase success to get sys graphic config: %{public}s", graphicFilePath.c_str());
65 break;
66 }
67 }
68 if (!xmlSysDocument_) {
69 LOGE("ConfigXMLParserBase read system file failed");
70 return PARSE_SYS_FILE_LOAD_FAIL;
71 }
72 return PARSE_EXEC_SUCCESS;
73 }
74
ParsePerformanceConfigXMLWithBundleName(const std::string & bundleName)75 ParseErrCode ConfigXMLParserBase::ParsePerformanceConfigXMLWithBundleName(const std::string& bundleName)
76 {
77 if (!xmlSysDocument_) {
78 LOGE("ConfigXMLParserBase xmlSysDocument is empty, LoadGraphicConfiguration first");
79 return PARSE_SYS_FILE_LOAD_FAIL;
80 }
81 xmlNode* root = xmlDocGetRootElement(xmlSysDocument_);
82 if (root == nullptr) {
83 LOGE("ConfigXMLParserBase xmlDocGetRootElement failed");
84 return PARSE_GET_ROOT_FAIL;
85 }
86
87 auto ret = ParseInternalWithBundleName(*root, bundleName);
88 if (ret != PARSE_EXEC_SUCCESS) {
89 LOGE("ConfigXMLParserBase ParseInternalWithBundleName failed");
90 }
91 return ret;
92 }
93
ParseInternalWithBundleName(xmlNode & node,const std::string & bundleName)94 ParseErrCode ConfigXMLParserBase::ParseInternalWithBundleName(xmlNode& node, const std::string& bundleName)
95 {
96 // skip root node
97 xmlNode* currNode = node.children;
98 if (currNode == nullptr) {
99 return PARSE_GET_CHILD_FAIL;
100 }
101
102 // find first PerformanceOptConfig node
103 auto ret = PARSE_EXEC_SUCCESS;
104 for (; currNode; currNode = currNode->next) {
105 ret = ParseXmlNodeNameWithIndex(*currNode, PARSE_XML_PERFORMANCE_OPT_CONFIG);
106 if (ret == PARSE_EXEC_SUCCESS) {
107 break;
108 }
109 }
110 if (currNode == nullptr) {
111 return PARSE_XML_NAME_ERROR;
112 }
113
114 currNode = currNode->children;
115 if (currNode == nullptr) {
116 return PARSE_GET_CHILD_FAIL;
117 }
118
119 // find parse feature nodes
120 for (; currNode; currNode = currNode->next) {
121 if (ParseXmlNodeNameWithIndex(*currNode, PARSE_XML_BUNDLE_NAME) != PARSE_EXEC_SUCCESS) {
122 continue;
123 }
124
125 std::string xmlBundleName = ExtractPropertyValue("name", *currNode);
126 if (xmlBundleName == bundleName && currNode->children) {
127 ParseFeatures(*(currNode->children));
128 break;
129 }
130 }
131 return ret;
132 }
133
ParseFeatures(xmlNode & node)134 void ConfigXMLParserBase::ParseFeatures(xmlNode& node)
135 {
136 auto& featureMap = FeatureParamManager::GetInstance().featureParamMap_;
137
138 // travel features
139 xmlNode* currNode = &node;
140 for (; currNode; currNode = currNode->next) {
141 if (ParseXmlNodeNameWithIndex(*currNode, PARSE_XML_FEATURE) != PARSE_EXEC_SUCCESS) {
142 continue;
143 }
144
145 std::string featureName = ExtractPropertyValue("id", *currNode);
146 auto it = featureMap.find(featureName);
147 if (it != featureMap.end()) {
148 it->second->ParseFeatureParam(*currNode);
149 }
150 }
151 }
152
ExtractPropertyValue(const std::string & propName,xmlNode & node)153 std::string ConfigXMLParserBase::ExtractPropertyValue(const std::string& propName, xmlNode& node)
154 {
155 LOGD("ConfigXMLParserBase extracting value : %{public}s", propName.c_str());
156 std::string propValue = "";
157 xmlChar* tempValue = nullptr;
158
159 if (xmlHasProp(&node, reinterpret_cast<const xmlChar*>(propName.c_str()))) {
160 tempValue = xmlGetProp(&node, reinterpret_cast<const xmlChar*>(propName.c_str()));
161 }
162
163 if (tempValue != nullptr) {
164 LOGD("ConfigXMLParserBase not a empty tempValue");
165 propValue = reinterpret_cast<const char*>(tempValue);
166 xmlFree(tempValue);
167 tempValue = nullptr;
168 }
169
170 return propValue;
171 }
172
ParseXmlNodeNameWithIndex(xmlNode & node,uint32_t nodeNameIndex)173 ParseErrCode ConfigXMLParserBase::ParseXmlNodeNameWithIndex(xmlNode& node, uint32_t nodeNameIndex)
174 {
175 if (nodeNameIndex >= XML_NODE_NAME_ARRAY.size()) {
176 return PARSE_SIZE_ERROR;
177 }
178
179 if (xmlStrcasecmp(node.name, reinterpret_cast<const xmlChar*>(XML_NODE_NAME_ARRAY[nodeNameIndex].c_str())) != 0) {
180 return PARSE_XML_NAME_ERROR;
181 }
182
183 return PARSE_EXEC_SUCCESS;
184 }
185 } // namespace OHOS::Ace
186