1 /*
2 * Copyright (c) 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 #include "napi_data_ability_observer.h"
16
17 #include <uv.h>
18
19 #include "hilog_tag_wrapper.h"
20
21 using namespace OHOS::AAFwk;
22 using namespace OHOS::AppExecFwk;
23
24 namespace OHOS {
25 namespace AppExecFwk {
ReleaseJSCallback()26 void NAPIDataAbilityObserver::ReleaseJSCallback()
27 {
28 std::lock_guard<std::mutex> lock(mutex_);
29 if (ref_ == nullptr) {
30 TAG_LOGE(AAFwkTag::FA, "null ref_");
31 return;
32 }
33
34 if (isCallingback_) {
35 needRelease_ = true;
36 TAG_LOGW(AAFwkTag::FA, "calling back");
37 return;
38 }
39
40 SafeReleaseJSCallback();
41 TAG_LOGI(AAFwkTag::FA, "end");
42 }
43
SafeReleaseJSCallback()44 void NAPIDataAbilityObserver::SafeReleaseJSCallback()
45 {
46 uv_loop_s* loop = nullptr;
47 napi_get_uv_event_loop(env_, &loop);
48 if (loop == nullptr) {
49 TAG_LOGE(AAFwkTag::FA, "null loop");
50 return;
51 }
52
53 struct DelRefCallbackInfo {
54 napi_env env_;
55 napi_ref ref_;
56 };
57
58 DelRefCallbackInfo* delRefCallbackInfo = new DelRefCallbackInfo {
59 .env_ = env_,
60 .ref_ = ref_,
61 };
62
63 uv_work_t* work = new uv_work_t;
64 work->data = static_cast<void*>(delRefCallbackInfo);
65 int ret = uv_queue_work_with_qos(
66 loop, work, [](uv_work_t* work) {},
67 [](uv_work_t* work, int status) {
68 // JS Thread
69 if (work == nullptr) {
70 TAG_LOGE(AAFwkTag::FA, "null work");
71 return;
72 }
73 auto delRefCallbackInfo = reinterpret_cast<DelRefCallbackInfo*>(work->data);
74 if (delRefCallbackInfo == nullptr) {
75 TAG_LOGE(AAFwkTag::FA, "null delRefCallbackInfo");
76 delete work;
77 work = nullptr;
78 return;
79 }
80
81 napi_delete_reference(delRefCallbackInfo->env_, delRefCallbackInfo->ref_);
82 delete delRefCallbackInfo;
83 delRefCallbackInfo = nullptr;
84 delete work;
85 work = nullptr;
86 }, uv_qos_user_initiated);
87 if (ret != 0) {
88 if (delRefCallbackInfo != nullptr) {
89 delete delRefCallbackInfo;
90 delRefCallbackInfo = nullptr;
91 }
92 if (work != nullptr) {
93 delete work;
94 work = nullptr;
95 }
96 }
97 ref_ = nullptr;
98 }
99
SetEnv(const napi_env & env)100 void NAPIDataAbilityObserver::SetEnv(const napi_env &env)
101 {
102 env_ = env;
103 TAG_LOGI(AAFwkTag::FA, "end");
104 }
105
SetCallbackRef(const napi_ref & ref)106 void NAPIDataAbilityObserver::SetCallbackRef(const napi_ref &ref)
107 {
108 ref_ = ref;
109 TAG_LOGI(AAFwkTag::FA, "end");
110 }
111
OnChangeJSThreadWorker(uv_work_t * work,int status)112 static void OnChangeJSThreadWorker(uv_work_t *work, int status)
113 {
114 TAG_LOGI(AAFwkTag::FA, "called");
115 if (work == nullptr) {
116 TAG_LOGE(AAFwkTag::FA, "null work");
117 return;
118 }
119 DAHelperOnOffCB *onCB = (DAHelperOnOffCB *)work->data;
120 if (onCB == nullptr) {
121 TAG_LOGE(AAFwkTag::FA, "null onCB");
122 delete work;
123 work = nullptr;
124 return;
125 }
126
127 if (onCB->observer != nullptr) {
128 onCB->observer->CallJsMethod();
129 }
130
131 delete onCB;
132 onCB = nullptr;
133 delete work;
134 work = nullptr;
135 TAG_LOGI(AAFwkTag::FA, "end");
136 }
137
CallJsMethod()138 void NAPIDataAbilityObserver::CallJsMethod()
139 {
140 {
141 std::lock_guard<std::mutex> lock(mutex_);
142 if (ref_ == nullptr || env_ == nullptr) {
143 TAG_LOGW(AAFwkTag::FA, "invalid observer");
144 return;
145 }
146 isCallingback_ = true;
147 }
148 napi_value result[ARGS_TWO] = {nullptr};
149 result[PARAM0] = GetCallbackErrorValue(env_, NO_ERROR);
150 napi_value callback = nullptr;
151 napi_value undefined = nullptr;
152 napi_get_undefined(env_, &undefined);
153 napi_value callResult = nullptr;
154 napi_get_reference_value(env_, ref_, &callback);
155 napi_call_function(env_, undefined, callback, ARGS_TWO, &result[PARAM0], &callResult);
156
157 {
158 std::lock_guard<std::mutex> lock(mutex_);
159 if (needRelease_ && ref_ != nullptr) {
160 TAG_LOGI(AAFwkTag::FA, "to delete callback");
161 napi_delete_reference(env_, ref_);
162 ref_ = nullptr;
163 needRelease_ = false;
164 }
165 isCallingback_ = false;
166 }
167 }
168
OnChange()169 void NAPIDataAbilityObserver::OnChange()
170 {
171 if (ref_ == nullptr) {
172 TAG_LOGE(AAFwkTag::FA, "null ret");
173 return;
174 }
175 uv_loop_s *loop = nullptr;
176 napi_get_uv_event_loop(env_, &loop);
177 if (loop == nullptr) {
178 TAG_LOGE(AAFwkTag::FA, "null loop");
179 return;
180 }
181
182 uv_work_t *work = new uv_work_t;
183 DAHelperOnOffCB *onCB = new DAHelperOnOffCB;
184 onCB->observer = this;
185 work->data = static_cast<void *>(onCB);
186 int rev = uv_queue_work(
187 loop,
188 work,
189 [](uv_work_t *work) {},
190 OnChangeJSThreadWorker);
191 if (rev != 0) {
192 if (onCB != nullptr) {
193 delete onCB;
194 onCB = nullptr;
195 }
196 if (work != nullptr) {
197 delete work;
198 work = nullptr;
199 }
200 }
201 TAG_LOGI(AAFwkTag::FA, "end");
202 }
203
204 } // namespace AppExecFwk
205 } // namespace OHOS