1 /*
2  * Copyright (c) 2023-2024 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 "js_ability_auto_startup_callback.h"
17 
18 #include "hilog_tag_wrapper.h"
19 #include "js_ability_auto_startup_manager_utils.h"
20 #include "js_runtime.h"
21 #include "js_runtime_utils.h"
22 
23 namespace OHOS {
24 namespace AbilityRuntime {
25 namespace {
26 const std::string METHOD_ON = "onAutoStartupOn";
27 const std::string METHOD_OFF = "onAutoStartupOff";
28 } // namespace
JsAbilityAutoStartupCallBack(napi_env env)29 JsAbilityAutoStartupCallBack::JsAbilityAutoStartupCallBack(napi_env env) : env_(env) {}
30 
~JsAbilityAutoStartupCallBack()31 JsAbilityAutoStartupCallBack::~JsAbilityAutoStartupCallBack() {}
32 
OnAutoStartupOn(const AutoStartupInfo & info)33 void JsAbilityAutoStartupCallBack::OnAutoStartupOn(const AutoStartupInfo &info)
34 {
35     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
36     JSCallFunction(info, METHOD_ON);
37 }
38 
OnAutoStartupOff(const AutoStartupInfo & info)39 void JsAbilityAutoStartupCallBack::OnAutoStartupOff(const AutoStartupInfo &info)
40 {
41     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
42     JSCallFunction(info, METHOD_OFF);
43 }
44 
Register(napi_value value)45 void JsAbilityAutoStartupCallBack::Register(napi_value value)
46 {
47     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
48     std::lock_guard<std::mutex> lock(mutexlock_);
49     for (const auto &callback : callbacks_) {
50         if (IsJsCallbackEquals(callback, value)) {
51             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "callback exist");
52             return;
53         }
54     }
55 
56     napi_ref ref = nullptr;
57     napi_create_reference(env_, value, 1, &ref);
58     callbacks_.emplace_back(std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference *>(ref)));
59 }
60 
UnRegister(napi_value value)61 void JsAbilityAutoStartupCallBack::UnRegister(napi_value value)
62 {
63     TAG_LOGD(AAFwkTag::AUTO_STARTUP, "called");
64     napi_valuetype type = napi_undefined;
65     napi_typeof(env_, value, &type);
66     std::lock_guard<std::mutex> lock(mutexlock_);
67     if (type == napi_undefined || type == napi_null) {
68         TAG_LOGD(AAFwkTag::AUTO_STARTUP, "invalid callback, clear all callback");
69         callbacks_.clear();
70         return;
71     }
72 
73     for (auto item = callbacks_.begin(); item != callbacks_.end();) {
74         if (IsJsCallbackEquals(*item, value)) {
75             item = callbacks_.erase(item);
76         } else {
77             item++;
78         }
79     }
80 }
81 
IsCallbacksEmpty()82 bool JsAbilityAutoStartupCallBack::IsCallbacksEmpty()
83 {
84     return callbacks_.empty();
85 }
86 
JSCallFunction(const AutoStartupInfo & info,const std::string & methodName)87 void JsAbilityAutoStartupCallBack::JSCallFunction(const AutoStartupInfo &info, const std::string &methodName)
88 {
89     wptr<JsAbilityAutoStartupCallBack> stub = iface_cast<JsAbilityAutoStartupCallBack>(AsObject());
90     NapiAsyncTask::CompleteCallback complete = [stub, info, methodName](
91                                                    napi_env env, NapiAsyncTask &task, int32_t status) {
92         sptr<JsAbilityAutoStartupCallBack> obj = stub.promote();
93         if (obj == nullptr) {
94             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null obj");
95             return;
96         }
97 
98         obj->JSCallFunctionWorker(info, methodName);
99     };
100 
101     NapiAsyncTask::Schedule("JsAbilityAutoStartupCallBack::JSCallFunction:" + methodName, env_,
102         CreateAsyncTaskWithLastParam(env_, nullptr, nullptr, std::move(complete), nullptr));
103 }
104 
JSCallFunctionWorker(const AutoStartupInfo & info,const std::string & methodName)105 void JsAbilityAutoStartupCallBack::JSCallFunctionWorker(const AutoStartupInfo &info, const std::string &methodName)
106 {
107     std::lock_guard<std::mutex> lock(mutexlock_);
108     for (auto callback : callbacks_) {
109         if (callback == nullptr) {
110             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null callback");
111             continue;
112         }
113 
114         auto obj = callback->GetNapiValue();
115         if (obj == nullptr) {
116             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null obj");
117             continue;
118         }
119 
120         napi_value funcObject;
121         if (napi_get_named_property(env_, obj, methodName.c_str(), &funcObject) != napi_ok) {
122             TAG_LOGE(AAFwkTag::AUTO_STARTUP, "get func failed");
123             continue;
124         }
125 
126         napi_value argv[] = { CreateJsAutoStartupInfo(env_, info) };
127         napi_call_function(env_, obj, funcObject, ArraySize(argv), argv, nullptr);
128     }
129 }
130 
IsJsCallbackEquals(const std::shared_ptr<NativeReference> & callback,napi_value value)131 bool JsAbilityAutoStartupCallBack::IsJsCallbackEquals(const std::shared_ptr<NativeReference> &callback,
132     napi_value value)
133 {
134     if (callback == nullptr) {
135         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null callback");
136         return false;
137     }
138 
139     auto object = callback->GetNapiValue();
140     if (object == nullptr) {
141         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "null object");
142         return false;
143     }
144 
145     bool result = false;
146     if (napi_strict_equals(env_, object, value, &result) != napi_ok) {
147         TAG_LOGE(AAFwkTag::AUTO_STARTUP, "objects not match");
148         return false;
149     }
150 
151     return result;
152 }
153 } // namespace AbilityRuntime
154 } // namespace OHOS