• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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