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