1 /*
2 * Copyright (c) 2021 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 <string>
16 #include <set>
17
18 #include "hilog_wrapper.h"
19 #include "js_context_utils.h"
20 #include "js_data_struct_converter.h"
21 #include "js_runtime.h"
22 #include "js_runtime_utils.h"
23 #include "napi_common_want.h"
24 #include "napi_remote_object.h"
25 #include "ability_runtime/js_caller_complex.h"
26
27 namespace OHOS {
28 namespace AbilityRuntime {
29 namespace { // nameless
30 static std::map<NativeValueType, std::string> logcast = {
31 { NATIVE_UNDEFINED, std::string("NATIVE_UNDEFINED") },
32 { NATIVE_NULL, std::string("NATIVE_NULL") },
33 { NATIVE_BOOLEAN, std::string("NATIVE_BOOLEAN") },
34 { NATIVE_NUMBER, std::string("NATIVE_NUMBER") },
35 { NATIVE_STRING, std::string("NATIVE_STRING") },
36 { NATIVE_SYMBOL, std::string("NATIVE_SYMBOL") },
37 { NATIVE_OBJECT, std::string("NATIVE_OBJECT") },
38 { NATIVE_FUNCTION, std::string("NATIVE_FUNCTION") },
39 { NATIVE_EXTERNAL, std::string("NATIVE_EXTERNAL") },
40 { NATIVE_BIGINT, std::string("NATIVE_BIGINT") },
41 };
42
43 class JsCallerComplex {
44 public:
45 enum class OBJSTATE {
46 OBJ_NORMAL,
47 OBJ_EXECUTION,
48 OBJ_RELEASE
49 };
50
JsCallerComplex(NativeEngine & engine,std::shared_ptr<AbilityContext> context,sptr<IRemoteObject> callee,std::shared_ptr<CallerCallBack> callerCallBack)51 explicit JsCallerComplex(
52 NativeEngine& engine, std::shared_ptr<AbilityContext> context, sptr<IRemoteObject> callee,
53 std::shared_ptr<CallerCallBack> callerCallBack) : context_(context), callee_(callee),
54 releaseCallBackEngine_(engine), callerCallBackObj_(callerCallBack), jsreleaseCallBackObj_(nullptr)
55 {
56 AddJsCallerComplex(this);
57 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
58 currentState_ = OBJSTATE::OBJ_NORMAL;
59 };
~JsCallerComplex()60 virtual~JsCallerComplex()
61 {
62 RemoveJsCallerComplex(this);
63 };
64
ReleaseObject(JsCallerComplex * data)65 static bool ReleaseObject(JsCallerComplex* data)
66 {
67 HILOG_DEBUG("ReleaseObject begin %{public}p", data);
68 if (data == nullptr) {
69 HILOG_ERROR("ReleaseObject begin, but input parameters is nullptr");
70 return false;
71 }
72
73 if (!data->ChangeCurrentState(OBJSTATE::OBJ_RELEASE)) {
74 auto handler = data->GetEventHandler();
75 if (handler == nullptr) {
76 HILOG_ERROR("ReleaseObject error end, Get eventHandler failed");
77 return false;
78 }
79 auto releaseObjTask = [pdata = data] () {
80 if (!FindJsCallerComplex(pdata)) {
81 HILOG_ERROR("ReleaseObject error end, but input parameters does not found");
82 return;
83 }
84 ReleaseObject(pdata);
85 };
86
87 handler->PostTask(releaseObjTask, "FinalizerRelease");
88 return false;
89 } else {
90 // when the object is about to be destroyed, does not reset state
91 std::unique_ptr<JsCallerComplex> delObj(data);
92 }
93 HILOG_DEBUG("ReleaseObject success end %{public}p", data);
94 return true;
95 }
96
Finalizer(NativeEngine * engine,void * data,void * hint)97 static void Finalizer(NativeEngine* engine, void* data, void* hint)
98 {
99 HILOG_DEBUG("JsCallerComplex::%{public}s begin.", __func__);
100 if (data == nullptr) {
101 HILOG_ERROR("JsCallerComplex::%{public}s is called, but input parameters is nullptr", __func__);
102 return;
103 }
104
105 auto ptr = static_cast<JsCallerComplex*>(data);
106 if (!FindJsCallerComplex(ptr)) {
107 HILOG_ERROR("JsCallerComplex::%{public}s is called, but input parameters does not found", __func__);
108 return;
109 }
110
111 ReleaseObject(ptr);
112 HILOG_DEBUG("JsCallerComplex::%{public}s end.", __func__);
113 }
114
JsRelease(NativeEngine * engine,NativeCallbackInfo * info)115 static NativeValue* JsRelease(NativeEngine* engine, NativeCallbackInfo* info)
116 {
117 if (engine == nullptr || info == nullptr) {
118 HILOG_ERROR("JsCallerComplex::%{public}s is called, but input parameters %{public}s is nullptr",
119 __func__,
120 ((engine == nullptr) ? "engine" : "info"));
121 return nullptr;
122 }
123
124 auto object = CheckParamsAndGetThis<JsCallerComplex>(engine, info);
125 if (object == nullptr) {
126 HILOG_ERROR("JsCallerComplex::%{public}s is called, CheckParamsAndGetThis return nullptr", __func__);
127 return nullptr;
128 }
129
130 return object->ReleaseInner(*engine, *info);
131 }
132
JsSetOnReleaseCallBack(NativeEngine * engine,NativeCallbackInfo * info)133 static NativeValue* JsSetOnReleaseCallBack(NativeEngine* engine, NativeCallbackInfo* info)
134 {
135 if (engine == nullptr || info == nullptr) {
136 HILOG_ERROR("JsCallerComplex::%{public}s is called, but input parameters %{public}s is nullptr",
137 __func__,
138 ((engine == nullptr) ? "engine" : "info"));
139 return nullptr;
140 }
141
142 auto object = CheckParamsAndGetThis<JsCallerComplex>(engine, info);
143 if (object == nullptr) {
144 HILOG_ERROR("JsCallerComplex::%{public}s is called, CheckParamsAndGetThis return nullptr", __func__);
145 return nullptr;
146 }
147
148 return object->SetOnReleaseCallBackInner(*engine, *info);
149 }
150
AddJsCallerComplex(JsCallerComplex * ptr)151 static bool AddJsCallerComplex(JsCallerComplex* ptr)
152 {
153 if (ptr == nullptr) {
154 HILOG_ERROR("JsAbilityContext::%{public}s, input parameters is nullptr", __func__);
155 return false;
156 }
157
158 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
159 auto iter = jsCallerComplexManagerList.find(ptr);
160 if (iter != jsCallerComplexManagerList.end()) {
161 HILOG_ERROR("JsAbilityContext::%{public}s, ptr[%{public}p] address exists", __func__, ptr);
162 return false;
163 }
164
165 auto iterRet = jsCallerComplexManagerList.emplace(ptr);
166 HILOG_DEBUG("JsAbilityContext::%{public}s, execution ends and retval is %{public}s",
167 __func__, iterRet.second ? "true" : "false");
168 return iterRet.second;
169 }
170
RemoveJsCallerComplex(JsCallerComplex * ptr)171 static bool RemoveJsCallerComplex(JsCallerComplex* ptr)
172 {
173 if (ptr == nullptr) {
174 HILOG_ERROR("JsAbilityContext::%{public}s, input parameters is nullptr", __func__);
175 return false;
176 }
177
178 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
179 auto iter = jsCallerComplexManagerList.find(ptr);
180 if (iter == jsCallerComplexManagerList.end()) {
181 HILOG_ERROR("JsAbilityContext::%{public}s, input parameters[%{public}p] not found", __func__, ptr);
182 return false;
183 }
184
185 jsCallerComplexManagerList.erase(ptr);
186 HILOG_DEBUG("JsAbilityContext::%{public}s, called", __func__);
187 return true;
188 }
189
FindJsCallerComplex(JsCallerComplex * ptr)190 static bool FindJsCallerComplex(JsCallerComplex* ptr)
191 {
192 if (ptr == nullptr) {
193 HILOG_ERROR("JsAbilityContext::%{public}s, input parameters is nullptr", __func__);
194 return false;
195 }
196 auto ret = true;
197 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
198 auto iter = jsCallerComplexManagerList.find(ptr);
199 if (iter == jsCallerComplexManagerList.end()) {
200 ret = false;
201 }
202 HILOG_DEBUG("JsAbilityContext::%{public}s, execution ends and retval is %{public}s",
203 __func__, ret ? "true" : "false");
204 return ret;
205 }
206
FindJsCallerComplexAndChangeState(JsCallerComplex * ptr,OBJSTATE state)207 static bool FindJsCallerComplexAndChangeState(JsCallerComplex* ptr, OBJSTATE state)
208 {
209 if (ptr == nullptr) {
210 HILOG_ERROR("JsAbilityContext::%{public}s, input parameters is nullptr", __func__);
211 return false;
212 }
213
214 std::lock_guard<std::mutex> lck (jsCallerComplexMutex);
215 auto iter = jsCallerComplexManagerList.find(ptr);
216 if (iter == jsCallerComplexManagerList.end()) {
217 HILOG_ERROR("JsAbilityContext::%{public}s, execution end, but not found", __func__);
218 return false;
219 }
220
221 auto ret = ptr->ChangeCurrentState(state);
222 HILOG_DEBUG("JsAbilityContext::%{public}s, execution ends and ChangeCurrentState retval is %{public}s",
223 __func__, ret ? "true" : "false");
224
225 return ret;
226 }
227
GetRemoteObject()228 sptr<IRemoteObject> GetRemoteObject()
229 {
230 return callee_;
231 }
232
GetEventHandler()233 std::shared_ptr<AppExecFwk::EventHandler> GetEventHandler()
234 {
235 return handler_;
236 }
237
ChangeCurrentState(OBJSTATE state)238 bool ChangeCurrentState(OBJSTATE state)
239 {
240 auto ret = false;
241 if (stateMechanismMutex_.try_lock() == false) {
242 HILOG_ERROR("mutex try_lock false");
243 return ret;
244 }
245
246 if (currentState_ == OBJSTATE::OBJ_NORMAL) {
247 currentState_ = state;
248 ret = true;
249 HILOG_DEBUG("currentState_ == OBJSTATE::OBJ_NORMAL");
250 } else if (currentState_ == state) {
251 ret = true;
252 HILOG_DEBUG("currentState_ == state");
253 } else {
254 ret = false;
255 HILOG_DEBUG("ret = false");
256 }
257
258 stateMechanismMutex_.unlock();
259 return ret;
260 }
261
GetCurrentState()262 OBJSTATE GetCurrentState()
263 {
264 return currentState_;
265 }
266
StateReset()267 void StateReset()
268 {
269 currentState_ = OBJSTATE::OBJ_NORMAL;
270 }
271
272 private:
273
OnReleaseNotify(const std::string & str)274 void OnReleaseNotify(const std::string &str)
275 {
276 HILOG_DEBUG("OnReleaseNotify begin");
277 if (handler_ == nullptr) {
278 HILOG_ERROR("handler parameters error");
279 return;
280 }
281
282 auto task = [notify = this, &str] () {
283 if (!FindJsCallerComplex(notify)) {
284 HILOG_ERROR("ptr[%{public}p] not found, address error", notify);
285 return;
286 }
287 notify->OnReleaseNotifyTask(str);
288 };
289 handler_->PostSyncTask(task, "OnReleaseNotify");
290 HILOG_DEBUG("OnReleaseNotify end");
291 }
292
OnReleaseNotifyTask(const std::string & str)293 void OnReleaseNotifyTask(const std::string &str)
294 {
295 HILOG_DEBUG("OnReleaseNotifyTask begin %{public}p", this);
296 if (jsreleaseCallBackObj_ == nullptr) {
297 HILOG_ERROR("JsCallerComplex::%{public}s, jsreleaseObj is nullptr", __func__);
298 return;
299 }
300
301 NativeValue* value = jsreleaseCallBackObj_->Get();
302 NativeValue* callback = jsreleaseCallBackObj_->Get();
303 NativeValue* args[] = { CreateJsValue(releaseCallBackEngine_, str) };
304 releaseCallBackEngine_.CallFunction(value, callback, args, 1);
305 HILOG_DEBUG("OnReleaseNotifyTask CallFunction call done %{public}p", this);
306 callee_ = nullptr;
307 StateReset();
308 HILOG_DEBUG("OnReleaseNotifyTask end %{public}p", this);
309 }
310
ReleaseInner(NativeEngine & engine,NativeCallbackInfo & info)311 NativeValue* ReleaseInner(NativeEngine& engine, NativeCallbackInfo& info)
312 {
313 HILOG_DEBUG("JsCallerComplex::%{public}s, called", __func__);
314 if (callerCallBackObj_ == nullptr) {
315 HILOG_ERROR("JsCallerComplex::%{public}s, CallBacker is nullptr", __func__);
316 return CreateJsError(engine, -1, "CallerComplex callback is nullptr.");
317 }
318
319 auto context = context_.lock();
320 if (context == nullptr) {
321 HILOG_ERROR("JsCallerComplex::%{public}s, context is nullptr", __func__);
322 return CreateJsError(engine, -1, "CallerComplex get context failed.");
323 }
324
325 auto retErr = context->ReleaseAbility(callerCallBackObj_);
326 if (retErr != ERR_OK) {
327 HILOG_ERROR("JsCallerComplex::%{public}s, ReleaseAbility failed %{public}d",
328 __func__, static_cast<int>(retErr));
329 return CreateJsError(engine, -1, "CallerComplex get context failed.");
330 }
331
332 return engine.CreateUndefined();
333 }
334
SetOnReleaseCallBackInner(NativeEngine & engine,NativeCallbackInfo & info)335 NativeValue* SetOnReleaseCallBackInner(NativeEngine& engine, NativeCallbackInfo& info)
336 {
337 HILOG_DEBUG("JsCallerComplex::%{public}s, begin", __func__);
338 constexpr size_t ARGC_TWO = 2;
339 if (info.argc >= ARGC_TWO) {
340 HILOG_ERROR("JsCallerComplex::%{public}s, Invalid input params", __func__);
341 return CreateJsError(engine, -1, "CallerComplex on release CallBack input params error.");
342 }
343 if (!info.argv[0]->IsCallable()) {
344 HILOG_ERROR("JsCallerComplex::%{public}s, IsCallable is %{public}s.",
345 __func__, ((info.argv[0]->IsCallable()) ? "true" : "false"));
346 return CreateJsError(engine, -1, "CallerComplex on release CallBack input params not function.");
347 }
348
349 if (callerCallBackObj_ == nullptr) {
350 HILOG_ERROR("JsCallerComplex::%{public}s, param1 is nullptr", __func__);
351 return CreateJsError(engine, -1, "CallerComplex on release CallBacker is nullptr.");
352 }
353
354 auto param1 = info.argv[0];
355 if (param1 == nullptr) {
356 HILOG_ERROR("JsCallerComplex::%{public}s, param1 is nullptr", __func__);
357 return CreateJsError(engine, -1, "CallerComplex on release input params isn`t function.");
358 }
359
360 jsreleaseCallBackObj_.reset(releaseCallBackEngine_.CreateReference(param1, 1));
361 auto task = [notify = this] (const std::string &str) {
362 if (!FindJsCallerComplexAndChangeState(notify, OBJSTATE::OBJ_EXECUTION)) {
363 HILOG_ERROR("ptr[%{public}p] not found, address error", notify);
364 return;
365 }
366 notify->OnReleaseNotify(str);
367 };
368 callerCallBackObj_->SetOnRelease(task);
369 HILOG_DEBUG("JsCallerComplex::%{public}s, end", __func__);
370 return engine.CreateUndefined();
371 }
372
373 private:
374 std::weak_ptr<AbilityContext> context_;
375 sptr<IRemoteObject> callee_;
376 NativeEngine& releaseCallBackEngine_;
377 std::shared_ptr<CallerCallBack> callerCallBackObj_;
378 std::unique_ptr<NativeReference> jsreleaseCallBackObj_;
379 std::shared_ptr<AppExecFwk::EventHandler> handler_;
380 std::mutex stateMechanismMutex_;
381 OBJSTATE currentState_;
382
383 static std::set<JsCallerComplex*> jsCallerComplexManagerList;
384 static std::mutex jsCallerComplexMutex;
385 };
386
387 std::set<JsCallerComplex*> JsCallerComplex::jsCallerComplexManagerList;
388 std::mutex JsCallerComplex::jsCallerComplexMutex;
389 } // nameless
390
CreateJsCallerComplex(NativeEngine & engine,std::shared_ptr<AbilityContext> context,sptr<IRemoteObject> callee,std::shared_ptr<CallerCallBack> callerCallBack)391 NativeValue* CreateJsCallerComplex(
392 NativeEngine& engine, std::shared_ptr<AbilityContext> context, sptr<IRemoteObject> callee,
393 std::shared_ptr<CallerCallBack> callerCallBack)
394 {
395 HILOG_DEBUG("JsCallerComplex::%{public}s, begin", __func__);
396 if (callee == nullptr || callerCallBack == nullptr || context == nullptr) {
397 HILOG_ERROR("%{public}s is called, input params error. %{public}s is nullptr", __func__,
398 (callee == nullptr) ? ("callee") : ((context == nullptr) ? ("context") : ("callerCallBack")));
399 return engine.CreateUndefined();
400 }
401
402 NativeValue* objValue = engine.CreateObject();
403 NativeObject* object = ConvertNativeValueTo<NativeObject>(objValue);
404
405 auto jsCaller = std::make_unique<JsCallerComplex>(engine, context, callee, callerCallBack);
406 if (jsCaller == nullptr) {
407 HILOG_ERROR("%{public}s is called, but make_unique<JsCallerComplex> is nullptr", __func__);
408 return engine.CreateUndefined();
409 }
410
411 auto remoteObj = jsCaller->GetRemoteObject();
412 if (remoteObj == nullptr) {
413 HILOG_ERROR("%{public}s is called,remoteObj is nullptr", __func__);
414 return engine.CreateUndefined();
415 }
416
417 object->SetNativePointer(jsCaller.release(), JsCallerComplex::Finalizer, nullptr);
418 object->SetProperty("callee", CreateJsCalleeRemoteObject(engine, remoteObj));
419 BindNativeFunction(engine, *object, "release", JsCallerComplex::JsRelease);
420 BindNativeFunction(engine, *object, "onRelease", JsCallerComplex::JsSetOnReleaseCallBack);
421
422 HILOG_DEBUG("JsCallerComplex::%{public}s, end", __func__);
423 return objValue;
424 }
425
CreateJsCalleeRemoteObject(NativeEngine & engine,sptr<IRemoteObject> callee)426 NativeValue* CreateJsCalleeRemoteObject(NativeEngine& engine, sptr<IRemoteObject> callee)
427 {
428 if (callee == nullptr) {
429 HILOG_ERROR("%{public}s is called, input params is nullptr", __func__);
430 return engine.CreateUndefined();
431 }
432 napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(
433 reinterpret_cast<napi_env>(&engine), callee);
434 NativeValue* nativeRemoteObject = reinterpret_cast<NativeValue*>(napiRemoteObject);
435
436 if (nativeRemoteObject == nullptr) {
437 HILOG_ERROR("%{public}s is called, but remoteObj is nullptr", __func__);
438 }
439
440 return nativeRemoteObject;
441 }
442 } // AbilityRuntime
443 } // OHOS