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 "event_config.h"
17 #include "hilog_wrapper.h"
18
19 namespace {
20 constexpr const char *SYSTEM_PERIPHERAL_FAULT_NOTIFIER_CONFIG_PATH =
21 "/system/etc/peripheral/peripheral_fault_notifier_config.json";
22 constexpr const char *SYS_PROD_PERIPHERAL_FAULT_NOTIFIER_CONFIG_PATH =
23 "/sys_prod/etc/peripheral/peripheral_fault_notifier_config.json";
24 } // namespace
25 namespace OHOS {
26 namespace ExternalDeviceManager {
27 std::shared_ptr<EventConfig> EventConfig::instance_ = nullptr;
28 std::mutex EventConfig::mutex_;
GetInstance()29 EventConfig &EventConfig::GetInstance()
30 {
31 std::lock_guard<std::mutex> lock(mutex_);
32 if (instance_ == nullptr) {
33 instance_ = std::make_shared<EventConfig>();
34 }
35 return *(instance_.get());
36 }
37
GetFaultsInfoByDomain(const std::string & domain)38 std::vector<FaultInfo> EventConfig::GetFaultsInfoByDomain(const std::string &domain)
39 {
40 std::vector<FaultInfo> faults;
41 if (peripheralFaultsMap_.find(domain) == peripheralFaultsMap_.end()) {
42 EDM_LOGE(MODULE_SERVICE, "fail to get faults info by domain %{public}s", domain.c_str());
43 return faults;
44 }
45 return peripheralFaultsMap_[domain];
46 }
47
ExtractFaultInfo(const cJSON * faultItem)48 FaultInfo EventConfig::ExtractFaultInfo(const cJSON *faultItem)
49 {
50 FaultInfo faultInfo;
51 cJSON *nameObj = cJSON_GetObjectItemCaseSensitive(faultItem, "faultName");
52 if (nameObj && cJSON_IsString(nameObj) && (strlen(nameObj->valuestring) > 0)) {
53 faultInfo.faultName = nameObj->valuestring;
54 }
55
56 cJSON *typeObj = cJSON_GetObjectItemCaseSensitive(faultItem, "type");
57 if (typeObj && cJSON_IsString(typeObj) && (strlen(typeObj->valuestring) > 0)) {
58 faultInfo.type = typeObj->valuestring;
59 }
60
61 cJSON *titleObj = cJSON_GetObjectItemCaseSensitive(faultItem, "title");
62 if (titleObj && cJSON_IsString(titleObj) && (strlen(titleObj->valuestring) > 0)) {
63 faultInfo.title = titleObj->valuestring;
64 }
65
66 cJSON *msgObj = cJSON_GetObjectItemCaseSensitive(faultItem, "msg");
67 if (msgObj && cJSON_IsString(msgObj) && (strlen(msgObj->valuestring) > 0)) {
68 faultInfo.msg = msgObj->valuestring;
69 }
70
71 cJSON *uriObj = cJSON_GetObjectItemCaseSensitive(faultItem, "uri");
72 if (uriObj && cJSON_IsString(uriObj) && (strlen(uriObj->valuestring) > 0)) {
73 faultInfo.uri = uriObj->valuestring;
74 }
75 return faultInfo;
76 }
77
DeleteJsonObj(cJSON * obj)78 void EventConfig::DeleteJsonObj(cJSON *obj)
79 {
80 if (obj &&!cJSON_IsNull(obj)) {
81 cJSON_Delete(obj);
82 obj = nullptr;
83 }
84 }
85
ParseJsonFile(const std::string & targetPath,DomainFaultsMap & peripheralFaultMap)86 bool EventConfig::ParseJsonFile(const std::string &targetPath, DomainFaultsMap &peripheralFaultMap)
87 {
88 if (access(targetPath.c_str(), F_OK) != 0) {
89 EDM_LOGE(MODULE_SERVICE, "targetPath %{public}s invalid", targetPath.c_str());
90 return false;
91 }
92
93 std::ifstream file(targetPath.c_str(), std::ios::in | std::ios::binary);
94 std::string content(std::istreambuf_iterator<char> {file}, std::istreambuf_iterator<char> {});
95 file.close();
96
97 cJSON *root = cJSON_Parse(content.c_str());
98 if (!root) {
99 EDM_LOGE(MODULE_SERVICE, "%{public}s json parse error.", targetPath.c_str());
100 return false;
101 }
102
103 if (cJSON_IsNull(root) || !cJSON_IsArray(root)) {
104 EDM_LOGE(MODULE_SERVICE, "%{public}s json root error", targetPath.c_str());
105 DeleteJsonObj(root);
106 return false;
107 }
108
109 cJSON *item = nullptr;
110 cJSON_ArrayForEach(item, root)
111 {
112 std::string domain;
113 cJSON *domainObj = cJSON_GetObjectItemCaseSensitive(item, "domain");
114 if (!domainObj || !cJSON_IsString(domainObj) || (strlen(domainObj->valuestring) == 0)) {
115 EDM_LOGE(MODULE_SERVICE, "domain %{public}s is invalid.", targetPath.c_str());
116 DeleteJsonObj(root);
117 return false;
118 }
119
120 domain = domainObj->valuestring;
121 cJSON *faultArray = cJSON_GetObjectItemCaseSensitive(item, "fault");
122 if (!faultArray || cJSON_IsNull(faultArray) || !cJSON_IsArray(faultArray)) {
123 EDM_LOGE(MODULE_SERVICE, "%{public}s faultArray invalid.", targetPath.c_str());
124 DeleteJsonObj(root);
125 return false;
126 }
127
128 cJSON *faultItem = nullptr;
129 std::vector<FaultInfo> faults;
130 cJSON_ArrayForEach(faultItem, faultArray)
131 {
132 faults.push_back(ExtractFaultInfo(faultItem));
133 }
134
135 peripheralFaultMap[domain] = faults;
136 }
137
138 DeleteJsonObj(root);
139 return true;
140 }
141
FillFaultsMap(const DomainFaultsMap & ccmMap,const DomainFaultsMap & localMap)142 DomainFaultsMap EventConfig::FillFaultsMap(const DomainFaultsMap &ccmMap, const DomainFaultsMap &localMap)
143 {
144 DomainFaultsMap resMap;
145 DomainFaultsMap tempMap(localMap);
146
147 for (const auto &[domain, ccmFaults] : ccmMap) {
148 auto localIt = tempMap.find(domain);
149 if (localIt == tempMap.end()) {
150 EDM_LOGE(MODULE_SERVICE, "domain %{public}s has been configured in CCMMap but not configured in localMap",
151 domain.c_str());
152 continue;
153 }
154 const auto& localFaults = localIt->second;
155 std::vector<FaultInfo> matchedFaults;
156 for (const auto& ccmFault : ccmFaults) {
157 auto it = std::find_if(localFaults.begin(), localFaults.end(),
158 [&ccmFault](const FaultInfo& localFault) {
159 return localFault.faultName == ccmFault.faultName;
160 });
161 if (it != localFaults.end()) {
162 matchedFaults.push_back(*it);
163 } else {
164 EDM_LOGE(MODULE_SERVICE,
165 "domain %{public}s and faultName %{public}s has been configured in CCMMap but not configured in "
166 "localMap",
167 domain.c_str(), ccmFault.faultName.c_str());
168 }
169 }
170 if (matchedFaults.size() < localFaults.size()) {
171 EDM_LOGE(MODULE_SERVICE, "localConfig has different faults with CCM for domain %{public}s", domain.c_str());
172 }
173 if (!matchedFaults.empty()) {
174 resMap[domain] = std::move(matchedFaults);
175 }
176 tempMap.erase(localIt);
177 }
178 if (!tempMap.empty()) {
179 EDM_LOGE(MODULE_SERVICE, "localMap contains %{public}lu domains that are not present in CCMMap",
180 static_cast<unsigned long>(tempMap.size()));
181 }
182 return resMap;
183 }
184
ParseJsonFile()185 bool EventConfig::ParseJsonFile()
186 {
187 peripheralFaultsMap_.clear();
188 DomainFaultsMap ccmMap;
189 DomainFaultsMap localMap;
190 bool bRet = ParseJsonFile(SYS_PROD_PERIPHERAL_FAULT_NOTIFIER_CONFIG_PATH, ccmMap);
191 if (!bRet || ccmMap.size() == 0) {
192 EDM_LOGE(MODULE_SERVICE, "Failed to parse the CCM configuration file");
193 return false;
194 }
195 bRet = ParseJsonFile(SYSTEM_PERIPHERAL_FAULT_NOTIFIER_CONFIG_PATH, localMap);
196 if (!bRet || localMap.size() == 0) {
197 EDM_LOGE(MODULE_SERVICE, "Failed to parse the local configuration file");
198 return false;
199 }
200 peripheralFaultsMap_ = FillFaultsMap(ccmMap, localMap);
201 if (peripheralFaultsMap_.empty()) {
202 EDM_LOGE(MODULE_SERVICE, "Failed to ParseJsonFile and peripheralFaultsMap_ is empty");
203 return false;
204 }
205 return true;
206 }
207
GetFaultInfo(const std::string & domain,const std::string & faultName) const208 FaultInfo EventConfig::GetFaultInfo(const std::string &domain, const std::string &faultName) const
209 {
210 FaultInfo faultInfo;
211 auto it = peripheralFaultsMap_.find(domain);
212 if (it != peripheralFaultsMap_.end()) {
213 for (const auto &fault : it->second) {
214 if (fault.faultName == faultName) {
215 return fault;
216 }
217 }
218 }
219 return faultInfo;
220 }
221 } // namespace ExternalDeviceManager
222 } // namespace OHOS
223