• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 #include "listener_base.h"
16 
17 #include <memory>
18 #include <uv.h>
19 
20 #include "camera_log.h"
21 #include "js_native_api.h"
22 #include "js_native_api_types.h"
23 
24 namespace OHOS {
25 namespace CameraStandard {
ListenerBase(napi_env env)26 ListenerBase::ListenerBase(napi_env env) : env_(env)
27 {
28     MEDIA_DEBUG_LOG("ListenerBase is called.");
29     auto ret = napi_add_env_cleanup_hook(env_, ListenerBase::CleanUp, this);
30     if (ret != napi_status::napi_ok) {
31         MEDIA_ERR_LOG("add env hook error: %{public}d", ret);
32     }
33 }
34 
~ListenerBase()35 ListenerBase::~ListenerBase()
36 {
37     MEDIA_DEBUG_LOG("~ListenerBase is called.");
38     auto ret = napi_remove_env_cleanup_hook(env_, ListenerBase::CleanUp, this);
39     if (ret != napi_status::napi_ok) {
40         MEDIA_ERR_LOG("remove env hook error: %{public}d", ret);
41     }
42 }
43 
ExecuteCallbackData(napi_env env,napi_value errCode,napi_value returnData)44 ListenerBase::ExecuteCallbackData::ExecuteCallbackData(napi_env env, napi_value errCode, napi_value returnData)
45     : env_(env), errCode_(errCode), returnData_(returnData) {};
46 
SaveCallbackReference(const std::string eventName,napi_value callback,bool isOnce)47 void ListenerBase::SaveCallbackReference(const std::string eventName, napi_value callback, bool isOnce)
48 {
49     CHECK_RETURN_ELOG(callback == nullptr,
50         "SaveCallbackReference:%s js callback is nullptr, save nothing", eventName.c_str());
51     napi_valuetype valueType = napi_undefined;
52     napi_typeof(env_, callback, &valueType);
53     CHECK_RETURN_ELOG(valueType != napi_function,
54         "SaveCallbackReference:%s js callback valueType is not function", eventName.c_str());
55     auto& callbackList = GetCallbackList(eventName);
56     std::lock_guard<std::mutex> lock(callbackList.listMutex);
57     for (auto it = callbackList.refList.begin(); it != callbackList.refList.end(); ++it) {
58         bool isSameCallback = CameraNapiUtils::IsSameNapiValue(env_, callback, it->GetCallbackFunction());
59         CHECK_RETURN_ELOG(isSameCallback, "SaveCallbackReference: has same callback, nothing to do");
60     }
61     callbackList.refList.emplace_back(AutoRef(env_, callback, isOnce));
62     MEDIA_DEBUG_LOG("Save callback reference success, %s callback list size [%{public}zu]", eventName.c_str(),
63         callbackList.refList.size());
64 }
65 
RemoveCallbackRef(const std::string eventName,napi_value callback)66 void ListenerBase::RemoveCallbackRef(const std::string eventName, napi_value callback)
67 {
68     if (callback == nullptr) {
69         MEDIA_INFO_LOG("RemoveCallbackReference: js callback is nullptr, remove all callback reference");
70         RemoveAllCallbacks(eventName);
71         return;
72     }
73     auto& callbackList = GetCallbackList(eventName);
74     std::lock_guard<std::mutex> lock(callbackList.listMutex);
75     for (auto it = callbackList.refList.begin(); it != callbackList.refList.end(); ++it) {
76         bool isSameCallback = CameraNapiUtils::IsSameNapiValue(env_, callback, it->GetCallbackFunction());
77         if (isSameCallback) {
78             MEDIA_INFO_LOG("RemoveCallbackReference: find %s callback, delete it", eventName.c_str());
79             callbackList.refList.erase(it);
80             return;
81         }
82     }
83     MEDIA_INFO_LOG("RemoveCallbackReference: %s callback not find", eventName.c_str());
84 }
85 
ExecuteCallback(const std::string eventName,const ExecuteCallbackNapiPara & callbackPara) const86 void ListenerBase::ExecuteCallback(const std::string eventName, const ExecuteCallbackNapiPara& callbackPara) const
87 {
88     MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallback is called");
89     auto& callbackList = GetCallbackList(eventName);
90     std::lock_guard<std::mutex> lock(callbackList.listMutex);
91     for (auto it = callbackList.refList.begin(); it != callbackList.refList.end();) {
92         napi_call_function(env_, callbackPara.recv, it->GetCallbackFunction(), callbackPara.argc, callbackPara.argv,
93             callbackPara.result);
94         if (it->isOnce_) {
95             MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallback, once to del %s", eventName.c_str());
96             it = callbackList.refList.erase(it);
97         } else {
98             it++;
99         }
100     }
101     MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallback, %s callback list size [%{public}zu]", eventName.c_str(),
102         callbackList.refList.size());
103 }
104 
ExecuteCallbackScopeSafe(const std::string eventName,const std::function<ExecuteCallbackData ()> fun) const105 void ListenerBase::ExecuteCallbackScopeSafe(
106     const std::string eventName, const std::function<ExecuteCallbackData()> fun) const
107 {
108     napi_handle_scope scope_ = nullptr;
109     if (!env_) {
110         MEDIA_ERR_LOG("ListenerBase::ExecuteCallbackScopeSafe env is nullptr");
111         return;
112     }
113     napi_open_handle_scope(env_, &scope_);
114 
115     MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallbackScopeSafe %{public}s is called", eventName.c_str());
116     auto& callbackList = GetCallbackList(eventName);
117     std::lock_guard<std::mutex> lock(callbackList.listMutex);
118     for (auto it = callbackList.refList.begin(); it != callbackList.refList.end();) {
119         // Do not move this call out of loop.
120         ExecuteCallbackData callbackData = fun();
121         if (callbackData.env_ == nullptr) {
122             MEDIA_ERR_LOG("ExecuteCallbackScopeSafe %{public}s env is null ", eventName.c_str());
123             continue;
124         }
125 
126         napi_value result[ARGS_TWO] = { nullptr, nullptr };
127         napi_value retVal;
128         result[0] = callbackData.errCode_;
129         result[1] = callbackData.returnData_;
130 
131         napi_call_function(callbackData.env_, nullptr, it->GetCallbackFunction(), ARGS_TWO, result, &retVal);
132         if (it->isOnce_) {
133             it = callbackList.refList.erase(it);
134         } else {
135             it++;
136         }
137     }
138     MEDIA_DEBUG_LOG("ListenerBase::ExecuteCallbackScopeSafe, %s callback list size [%{public}zu]", eventName.c_str(),
139         callbackList.refList.size());
140 
141     napi_close_handle_scope(env_, scope_);
142 }
143 
RemoveAllCallbacks(const std::string eventName)144 void ListenerBase::RemoveAllCallbacks(const std::string eventName)
145 {
146     auto& callbackList = GetCallbackList(eventName);
147     std::lock_guard<std::mutex> lock(callbackList.listMutex);
148     callbackList.refList.clear();
149     MEDIA_INFO_LOG("RemoveAllCallbacks: remove all js callbacks success");
150 }
151 
IsEmpty(const std::string eventName) const152 bool ListenerBase::IsEmpty(const std::string eventName) const
153 {
154     auto& callbackList = GetCallbackList(eventName);
155     std::lock_guard<std::mutex> lock(callbackList.listMutex);
156     return callbackList.refList.empty();
157 }
158 
CleanUp(void * data)159 void ListenerBase::CleanUp(void* data)
160 {
161     MEDIA_INFO_LOG("ListenerBase::CleanUp enter");
162     ListenerBase* listener = reinterpret_cast<ListenerBase*>(data);
163     if (!listener) {
164         return;
165     }
166     listener->CleanUpImpl();
167 }
168 
CleanUpImpl()169 void ListenerBase::CleanUpImpl()
170 {
171     MEDIA_INFO_LOG("ListenerBase::CleanUpImpl enter");
172     ClearNamedCallbackMap();
173     env_ = nullptr;
174 }
175 
176 } // namespace CameraStandard
177 } // namespace OHOS
178