1 /*
2 * Copyright (c) 2022-2023 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 "devicestatus_event.h"
17
18 #include <js_native_api.h>
19 #include <map>
20 #include <uv.h>
21
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24
25 #include "devicestatus_define.h"
26
27 namespace OHOS {
28 namespace Msdp {
29 namespace DeviceStatus {
30 namespace {
31 constexpr ::OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "DeviceStatusEvent" };
32 constexpr size_t EVENT_MAP_MAX { 20 };
33 } // namespace
34
DeviceStatusEvent(napi_env env)35 DeviceStatusEvent::DeviceStatusEvent(napi_env env)
36 {
37 env_ = env;
38 }
39
~DeviceStatusEvent()40 DeviceStatusEvent::~DeviceStatusEvent()
41 {
42 eventOnceMap_.clear();
43 eventMap_.clear();
44 }
45
On(int32_t eventType,napi_value handler,bool isOnce)46 bool DeviceStatusEvent::On(int32_t eventType, napi_value handler, bool isOnce)
47 {
48 FI_HILOGD("On for event:%{public}d, isOnce:%{public}d", eventType, isOnce);
49 if ((eventMap_.size() > EVENT_MAP_MAX) || (eventOnceMap_.size() > EVENT_MAP_MAX)) {
50 FI_HILOGE("EventMap_ or eventOnceMap_ size over");
51 return false;
52 }
53 napi_handle_scope scope = nullptr;
54 napi_open_handle_scope(env_, &scope);
55 CHKPF(scope);
56 napi_ref onHandlerRef = nullptr;
57 napi_status status = napi_ok;
58 if (isOnce) {
59 auto iter = eventOnceMap_.find(eventType);
60 if (iter == eventOnceMap_.end()) {
61 FI_HILOGD("EventType:%{public}d not exists", eventType);
62 eventOnceMap_[eventType] = std::list<std::shared_ptr<DeviceStatusEventListener>>();
63 }
64 status = napi_create_reference(env_, handler, 1, &onHandlerRef);
65 if (status != napi_ok) {
66 FI_HILOGE("Failed to create reference");
67 napi_close_handle_scope(env_, scope);
68 return false;
69 }
70 auto listener = std::make_shared<DeviceStatusEventListener>();
71 listener->onHandlerRef = onHandlerRef;
72 eventOnceMap_[eventType].push_back(listener);
73 FI_HILOGI("Add once handler to list %{public}d", eventType);
74 } else {
75 auto iter = eventMap_.find(eventType);
76 if (iter == eventMap_.end()) {
77 FI_HILOGD("EventType:%{public}d not exists", eventType);
78 eventMap_[eventType] = std::list<std::shared_ptr<DeviceStatusEventListener>>();
79 }
80 status = napi_create_reference(env_, handler, 1, &onHandlerRef);
81 if (status != napi_ok) {
82 FI_HILOGE("Failed to create reference");
83 napi_close_handle_scope(env_, scope);
84 return false;
85 }
86 auto listener = std::make_shared<DeviceStatusEventListener>();
87 listener->onHandlerRef = onHandlerRef;
88 eventMap_[eventType].push_back(listener);
89 FI_HILOGI("Add handler to list %{public}d", eventType);
90 }
91 napi_close_handle_scope(env_, scope);
92 return true;
93 }
94
Off(int32_t eventType,napi_value handler)95 bool DeviceStatusEvent::Off(int32_t eventType, napi_value handler)
96 {
97 FI_HILOGD("DeviceStatusEvent off in for event:%{public}d", eventType);
98 auto iter = eventMap_.find(eventType);
99 if (iter == eventMap_.end()) {
100 FI_HILOGE("EventType %{public}d not found", eventType);
101 return false;
102 }
103 bool equal = false;
104 napi_value result = nullptr;
105
106 for (auto listener : eventMap_[eventType]) {
107 napi_status status = napi_get_reference_value(env_, listener->onHandlerRef, &result);
108 if (status != napi_ok) {
109 FI_HILOGE("Failed to get_reference_value");
110 return false;
111 }
112 status = napi_strict_equals(env_, result, handler, &equal);
113 if (status != napi_ok) {
114 FI_HILOGE("Failed to strict_equals");
115 return false;
116 }
117 if (equal) {
118 FI_HILOGI("Delete handler from list %{public}d", eventType);
119 status = napi_delete_reference(env_, listener->onHandlerRef);
120 if (status != napi_ok) {
121 FI_HILOGW("Delete failed");
122 }
123 eventMap_[eventType].remove(listener);
124 break;
125 }
126 }
127 FI_HILOGI("%{public}zu listeners in the list of %{public}d",
128 eventMap_[eventType].size(), eventType);
129 return eventMap_[eventType].empty();
130 }
131
OffOnce(int32_t eventType,napi_value handler)132 bool DeviceStatusEvent::OffOnce(int32_t eventType, napi_value handler)
133 {
134 FI_HILOGD("DeviceStatusEvent OffOnce in for event:%{public}d", eventType);
135 auto iter = eventOnceMap_.find(eventType);
136 if (iter == eventOnceMap_.end()) {
137 FI_HILOGE("EventType %{public}d not found", eventType);
138 return false;
139 }
140 bool equal = false;
141 napi_value result = nullptr;
142 for (auto listener : eventOnceMap_[eventType]) {
143 napi_get_reference_value(env_, listener->onHandlerRef, &result);
144 napi_strict_equals(env_, result, handler, &equal);
145 if (equal) {
146 FI_HILOGI("Delete once handler from list %{public}d", eventType);
147 napi_status status = napi_delete_reference(env_, listener->onHandlerRef);
148 if (status != napi_ok) {
149 FI_HILOGW("Delete failed");
150 }
151 eventOnceMap_[eventType].remove(listener);
152 break;
153 }
154 }
155 FI_HILOGI("%{public}zu listeners in the once list of %{public}d",
156 eventOnceMap_[eventType].size(), eventType);
157 return eventMap_[eventType].empty();
158 }
159
RemoveAllCallback(int32_t eventType)160 bool DeviceStatusEvent::RemoveAllCallback(int32_t eventType)
161 {
162 CALL_DEBUG_ENTER;
163 auto iter = eventMap_.find(eventType);
164 if (iter == eventMap_.end()) {
165 FI_HILOGE("EvenType %{public}d not found", eventType);
166 return false;
167 }
168 eventMap_.erase(eventType);
169 return true;
170 }
171
CheckRet(int32_t eventType,size_t argc,int32_t value,std::shared_ptr<DeviceStatusEventListener> & typeHandler)172 void DeviceStatusEvent::CheckRet(int32_t eventType, size_t argc, int32_t value,
173 std::shared_ptr<DeviceStatusEventListener> &typeHandler)
174 {
175 CHKPV(typeHandler);
176 napi_handle_scope scope = nullptr;
177 napi_open_handle_scope(env_, &scope);
178 CHKPV(scope);
179 napi_value handler = nullptr;
180 napi_status status = napi_ok;
181 status = napi_get_reference_value(env_, typeHandler->onHandlerRef, &handler);
182 if (status != napi_ok) {
183 FI_HILOGE("OnEvent handler for %{public}d failed, status:%{public}d", eventType, status);
184 napi_close_handle_scope(env_, scope);
185 return;
186 }
187 napi_value result = nullptr;
188 SendRet(eventType, value, result);
189 napi_value callResult = nullptr;
190 FI_HILOGD("Report to hap");
191 status = napi_call_function(env_, nullptr, handler, argc, &result, &callResult);
192 if (status != napi_ok) {
193 FI_HILOGE("CheckRet:napi_call_function for %{public}d failed, status:%{public}d", eventType, status);
194 napi_close_handle_scope(env_, scope);
195 return;
196 }
197 napi_close_handle_scope(env_, scope);
198 }
199
SendRet(int32_t eventType,int32_t value,napi_value & result)200 void DeviceStatusEvent::SendRet(int32_t eventType, int32_t value, napi_value &result)
201 {
202 napi_status status = napi_create_object(env_, &result);
203 if (status != napi_ok) {
204 FI_HILOGE("Failed to create object");
205 return;
206 }
207 napi_value tmpValue = nullptr;
208 status = napi_create_int32(env_, eventType, &tmpValue);
209 if (status != napi_ok) {
210 FI_HILOGE("Failed to create object");
211 return;
212 }
213 status = napi_set_named_property(env_, result, "type", tmpValue);
214 if (status != napi_ok) {
215 FI_HILOGE("Failed to set name");
216 return;
217 }
218
219 status = napi_create_int32(env_, value, &tmpValue);
220 if (status != napi_ok) {
221 FI_HILOGE("Failed to create value");
222 return;
223 }
224 status = napi_set_named_property(env_, result, "value", tmpValue);
225 if (status != napi_ok) {
226 FI_HILOGE("Failed to set_named");
227 return;
228 }
229 }
230
OnEvent(int32_t eventType,size_t argc,int32_t value,bool isOnce)231 void DeviceStatusEvent::OnEvent(int32_t eventType, size_t argc, int32_t value, bool isOnce)
232 {
233 CALL_DEBUG_ENTER;
234 FI_HILOGD("OnEvent for %{public}d, isOnce:%{public}d", eventType, isOnce);
235 napi_handle_scope scope = nullptr;
236 napi_open_handle_scope(env_, &scope);
237 CHKPV(scope);
238 std::map<int32_t, std::list<std::shared_ptr<DeviceStatusEventListener>>>::iterator typeHandler;
239 if (isOnce) {
240 typeHandler = eventOnceMap_.find(eventType);
241 if (typeHandler == eventOnceMap_.end()) {
242 FI_HILOGE("OnEvent eventType %{public}d not found", eventType);
243 napi_close_handle_scope(env_, scope);
244 return;
245 }
246 } else {
247 typeHandler = eventMap_.find(eventType);
248 if (typeHandler == eventMap_.end()) {
249 FI_HILOGE("OnEvent:eventType %{public}d not found", eventType);
250 napi_close_handle_scope(env_, scope);
251 return;
252 }
253 }
254 FI_HILOGD("%{public}zu callbacks of eventType %{public}d are sent",
255 typeHandler->second.size(), eventType);
256 for (auto handler : typeHandler->second) {
257 CheckRet(eventType, argc, value, handler);
258 }
259 napi_close_handle_scope(env_, scope);
260 }
261
ClearEventMap()262 void DeviceStatusEvent::ClearEventMap()
263 {
264 for (const auto &iter : eventMap_) {
265 for (const auto &eventListener : iter.second) {
266 napi_status status = napi_delete_reference(env_, eventListener->onHandlerRef);
267 if (status != napi_ok) {
268 FI_HILOGW("Failed to delete reference");
269 }
270 }
271 }
272 for (const auto &iter : eventOnceMap_) {
273 for (const auto &eventListener : iter.second) {
274 napi_status status = napi_delete_reference(env_, eventListener->onHandlerRef);
275 if (status != napi_ok) {
276 FI_HILOGW("Failed to delete reference");
277 napi_delete_reference(env_, eventListener->onHandlerRef);
278 }
279 }
280 }
281 eventMap_.clear();
282 eventOnceMap_.clear();
283 }
284 } // namespace DeviceStatus
285 } // namespace Msdp
286 } // namespace OHOS
287