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