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 "ani_async_callback_manager.h"
17 #include "event_logger.h"
18 #include "ani_deserialize.h"
19
20 namespace OHOS {
21 namespace AppExecFwk {
22 namespace {
23 DEFINE_EH_HILOG_LABEL("EventsEmitter");
24 constexpr const char* EVENT_DATA = "eventData";
25 constexpr const char* GENERIC_EVENT_DATA = "genericEventData";
26 }
27
~AniAsyncCallbackInfo()28 AniAsyncCallbackInfo::~AniAsyncCallbackInfo()
29 {
30 vm = nullptr;
31 }
32
ProcessEvent(const InnerEvent::Pointer & event)33 void AniAsyncCallbackInfo::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event)
34 {
35 if (vm == nullptr) {
36 return;
37 }
38 auto serializeData = event->GetSharedObject<SerializeData>();
39 auto t = std::thread(ThreadFunction, vm, callback, dataType, serializeData);
40 t.join();
41 if (once) {
42 isDeleted = true;
43 }
44 }
45
GetCallbackArgs(ani_env * env,std::string & dataType,std::vector<ani_ref> & args,std::shared_ptr<SerializeData> serializeData)46 ani_status AniAsyncCallbackInfo::GetCallbackArgs(
47 ani_env *env, std::string& dataType, std::vector<ani_ref>& args, std::shared_ptr<SerializeData> serializeData)
48 {
49 ani_ref eventData;
50 bool isDeserializeSuccess = false;
51 if (serializeData->envType == EnvType::ANI) {
52 isDeserializeSuccess = AniDeserialize::PeerDeserialize(env, &eventData, serializeData);
53 } else {
54 if (serializeData->isCrossRuntime) {
55 isDeserializeSuccess = AniDeserialize::CrossDeserialize(env, &eventData, serializeData);
56 }
57 }
58 if (!isDeserializeSuccess) {
59 return ANI_INVALID_ARGS;
60 }
61
62 ani_status status = ANI_OK;
63 ani_class cls;
64 if (dataType == EVENT_DATA) {
65 status = env->FindClass("L@ohos/events/emitter/emitter/EventDataInner;", &cls);
66 } else if (dataType == GENERIC_EVENT_DATA) {
67 status = env->FindClass("L@ohos/events/emitter/emitter/GenericEventDataInner;", &cls);
68 } else {
69 return status;
70 }
71 if (status != ANI_OK) {
72 HILOGE("threadFunciton FindClass error%{public}d", status);
73 return status;
74 }
75 ani_method ctor;
76 status = env->Class_FindMethod(cls, "<ctor>", ":V", &ctor);
77 if (status != ANI_OK) {
78 HILOGE("threadFunciton Class_FindMethod error%{public}d", status);
79 return status;
80 }
81 ani_object obj;
82 status = env->Object_New(cls, ctor, &obj);
83 if (status != ANI_OK) {
84 HILOGE("threadFunciton Object_New error%{public}d", status);
85 return status;
86 }
87
88 env->Object_SetPropertyByName_Ref(obj, "data", eventData);
89 args.push_back(reinterpret_cast<ani_ref>(obj));
90 return status;
91 }
92
ThreadFunction(ani_vm * vm,ani_ref callback,std::string dataType,std::shared_ptr<SerializeData> serializeData)93 void AniAsyncCallbackInfo::ThreadFunction(
94 ani_vm* vm, ani_ref callback, std::string dataType, std::shared_ptr<SerializeData> serializeData)
95 {
96 ani_env *env;
97 ani_status status = ANI_OK;
98 ani_option interopEnabled {"--interop=disable", nullptr};
99 ani_options aniArgs {1, &interopEnabled};
100 status = vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env);
101 if (ANI_OK != status) {
102 HILOGE("vm GetEnv error %{public}d", status);
103 return;
104 }
105
106 auto fnObj = reinterpret_cast<ani_fn_object>(callback);
107 if (fnObj == nullptr) {
108 HILOGE("threadFunciton fnObj is nullptr");
109 vm->DetachCurrentThread();
110 return;
111 }
112 std::vector<ani_ref> args;
113 ani_ref result;
114 status = AniAsyncCallbackInfo::GetCallbackArgs(env, dataType, args, serializeData);
115 if (status != ANI_OK) {
116 HILOGI("Get callback args failed. error %{public}d", status);
117 vm->DetachCurrentThread();
118 return;
119 }
120 status = env->FunctionalObject_Call(fnObj, args.size(), args.data(), &result);
121 if (ANI_OK != status) {
122 HILOGI("ANI call function failed. error %{public}d", status);
123 }
124
125 vm->DetachCurrentThread();
126 }
127
AniDeleteCallbackInfoByEventId(const InnerEvent::EventId & eventIdValue)128 void AniAsyncCallbackManager::AniDeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue)
129 {
130 std::lock_guard<std::mutex> lock(aniAsyncCallbackContainerMutex_);
131 auto iter = aniAsyncCallbackContainer_.find(eventIdValue);
132 if (iter != aniAsyncCallbackContainer_.end()) {
133 for (auto callbackInfo : iter->second) {
134 callbackInfo->isDeleted = true;
135 }
136 }
137 aniAsyncCallbackContainer_.erase(eventIdValue);
138 }
139
AniGetListenerCountByEventId(const InnerEvent::EventId & eventId)140 uint32_t AniAsyncCallbackManager::AniGetListenerCountByEventId(const InnerEvent::EventId &eventId)
141 {
142 uint32_t cnt = 0u;
143 std::lock_guard<std::mutex> lock(aniAsyncCallbackContainerMutex_);
144 auto subscribe = aniAsyncCallbackContainer_.find(eventId);
145 if (subscribe != aniAsyncCallbackContainer_.end()) {
146 for (auto it = subscribe->second.begin(); it != subscribe->second.end();) {
147 if ((*it)->isDeleted == true || (*it)->vm == nullptr) {
148 it = subscribe->second.erase(it);
149 continue;
150 }
151 ++it;
152 ++cnt;
153 }
154 }
155 return cnt;
156 }
157
AniIsExistValidCallback(const InnerEvent::EventId & eventId)158 bool AniAsyncCallbackManager::AniIsExistValidCallback(const InnerEvent::EventId &eventId)
159 {
160 std::lock_guard<std::mutex> lock(aniAsyncCallbackContainerMutex_);
161 auto subscribe = aniAsyncCallbackContainer_.find(eventId);
162 if (subscribe == aniAsyncCallbackContainer_.end()) {
163 return false;
164 }
165 if (subscribe->second.size() != 0) {
166 return true;
167 }
168 return false;
169 }
170
AniInsertCallbackInfo(ani_env * env,InnerEvent::EventId eventId,bool once,ani_ref callback,ani_string dataType)171 void AniAsyncCallbackManager::AniInsertCallbackInfo(
172 ani_env *env, InnerEvent::EventId eventId, bool once, ani_ref callback, ani_string dataType)
173 {
174 std::lock_guard<std::mutex> lock(aniAsyncCallbackContainerMutex_);
175 ani_ref globalRefCallback;
176 env->GlobalReference_Create(callback, &globalRefCallback);
177 auto subscriber = aniAsyncCallbackContainer_.find(eventId);
178 if (subscriber != aniAsyncCallbackContainer_.end()) {
179 for (auto callbackInfo : subscriber->second) {
180 if (callbackInfo->isDeleted) {
181 continue;
182 }
183 ani_boolean isEq = false;
184 env->Reference_StrictEquals(globalRefCallback, callbackInfo->callback, &isEq);
185 if (!isEq) {
186 continue;
187 }
188 callbackInfo->once = once;
189 return;
190 }
191 }
192 auto callbackInfoPtr = new (std::nothrow) AniAsyncCallbackInfo();
193 if (!callbackInfoPtr) {
194 HILOGE("new object failed");
195 return;
196 }
197 std::shared_ptr<AniAsyncCallbackInfo> callbackInfo(callbackInfoPtr, [](AniAsyncCallbackInfo* callbackInfo) {
198 AniReleaseCallbackInfo(callbackInfo);
199 });
200 auto status = env->GetVM(&callbackInfo->vm);
201 if (callbackInfo->vm == nullptr) {
202 HILOGE("Get vm failed. status: %{public}d", status);
203 return;
204 }
205 callbackInfo->once = once;
206 callbackInfo->eventId = eventId;
207 callbackInfo->callback = globalRefCallback;
208 callbackInfo->dataType = AniGetStdString(env, dataType);
209 aniAsyncCallbackContainer_[eventId].insert(callbackInfo);
210 }
211
AniDeleteCallbackInfo(ani_env * env,const InnerEvent::EventId & eventIdValue,ani_ref callback)212 void AniAsyncCallbackManager::AniDeleteCallbackInfo(
213 ani_env *env, const InnerEvent::EventId &eventIdValue, ani_ref callback)
214 {
215 std::lock_guard<std::mutex> lock(aniAsyncCallbackContainerMutex_);
216 auto iter = aniAsyncCallbackContainer_.find(eventIdValue);
217 if (iter == aniAsyncCallbackContainer_.end()) {
218 return;
219 }
220 for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) {
221 ani_boolean isEq = false;
222 env->Reference_StrictEquals(callback, (*callbackInfo)->callback, &isEq);
223 if (!isEq) {
224 ++callbackInfo;
225 continue;
226 }
227 (*callbackInfo)->isDeleted = true;
228 callbackInfo = iter->second.erase(callbackInfo);
229 return;
230 }
231 }
232
AniGetAsyncCallbackInfo(const InnerEvent::EventId & eventId)233 std::unordered_set<std::shared_ptr<AniAsyncCallbackInfo>> AniAsyncCallbackManager::AniGetAsyncCallbackInfo(
234 const InnerEvent::EventId &eventId)
235 {
236 std::lock_guard<std::mutex> lock(aniAsyncCallbackContainerMutex_);
237 auto iter = aniAsyncCallbackContainer_.find(eventId);
238 if (iter == aniAsyncCallbackContainer_.end()) {
239 std::unordered_set<std::shared_ptr<AniAsyncCallbackInfo>> result;
240 return result;
241 }
242 for (auto it = iter->second.begin(); it != iter->second.end();) {
243 if (*it == nullptr || (*it)->isDeleted == true || (*it)->vm == nullptr) {
244 it = iter->second.erase(it);
245 continue;
246 }
247 ++it;
248 }
249 return iter->second;
250 }
251
AniDoCallback(const InnerEvent::Pointer & event)252 void AniAsyncCallbackManager::AniDoCallback(const InnerEvent::Pointer& event)
253 {
254 auto aniCallbackInfos = AniGetAsyncCallbackInfo(event->GetInnerEventIdEx());
255 for (auto it = aniCallbackInfos.begin(); it != aniCallbackInfos.end(); ++it) {
256 (*it)->ProcessEvent(event);
257 }
258 }
259
AniReleaseCallbackInfo(AniAsyncCallbackInfo * callbackInfo)260 void AniAsyncCallbackManager::AniReleaseCallbackInfo(AniAsyncCallbackInfo* callbackInfo)
261 {
262 if (callbackInfo != nullptr) {
263 ani_env *MyEnv;
264 if (ANI_OK != callbackInfo->vm->GetEnv(ANI_VERSION_1, &MyEnv)) {
265 ani_status status = ANI_OK;
266 ani_option interopEnabled {"--interop=disable", nullptr};
267 ani_options aniArgs {1, &interopEnabled};
268 status = callbackInfo->vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &MyEnv);
269 if (ANI_OK != status) {
270 HILOGE("attach thread failed");
271 delete callbackInfo;
272 callbackInfo = nullptr;
273 return;
274 }
275 status = MyEnv->GlobalReference_Delete(callbackInfo->callback);
276 if (status != ANI_OK) {
277 HILOGE("delete reference failed");
278 }
279 callbackInfo->vm->DetachCurrentThread();
280 delete callbackInfo;
281 callbackInfo = nullptr;
282 return;
283 }
284 MyEnv->GlobalReference_Delete(callbackInfo->callback);
285 delete callbackInfo;
286 callbackInfo = nullptr;
287 }
288 }
289
AniGetStdString(ani_env * env,ani_string str)290 std::string AniAsyncCallbackManager::AniGetStdString(ani_env *env, ani_string str)
291 {
292 std::string result;
293 ani_size sz {};
294 env->String_GetUTF8Size(str, &sz);
295 result.resize(sz + 1);
296 env->String_GetUTF8SubString(str, 0, sz, result.data(), result.size(), &sz);
297 result.resize(sz);
298 return result;
299 }
300
301 } // namespace AppExecFwk
302 } // namespace OHOS