1 /*
2 * Copyright (c) 2024-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 "uv.h"
17 #include "native_reference.h"
18 #include "native_value.h"
19 #include "b_error/b_error.h"
20 #include "general_callbacks.h"
21
22 namespace OHOS::FileManagement::Backup {
23 using namespace std;
24
RemoveCallbackRef()25 void GeneralCallbacks::RemoveCallbackRef()
26 {
27 HILOGI("Called RemoveCallbackRef");
28 onFileReady.CleanRef();
29 onBundleBegin.CleanRef();
30 onBundleEnd.CleanRef();
31 onAllBundlesEnd.CleanRef();
32 onBackupServiceDied.CleanRef();
33 onResultReport.CleanRef();
34 onProcess.CleanRef();
35 }
36
CleanRef()37 void BackupRestoreCallback::CleanRef()
38 {
39 HILOGI("BackupRestoreCallback CleanRef");
40 if (!ctx_) {
41 HILOGE("BackupRestoreCallback ctx is nullptr");
42 return;
43 }
44 if (!bool(ctx_->cb_)) {
45 HILOGE("BackupRestoreCallback ref is nullptr");
46 return;
47 }
48 ctx_->cb_.DeleteJsEnv();
49 }
50
BackupRestoreCallback(napi_env env,LibN::NVal thisPtr,LibN::NVal cb)51 BackupRestoreCallback::BackupRestoreCallback(napi_env env, LibN::NVal thisPtr, LibN::NVal cb) : env_(env)
52 {
53 ctx_ = new LibN::NAsyncContextCallback(thisPtr, cb);
54 }
55
~BackupRestoreCallback()56 BackupRestoreCallback::~BackupRestoreCallback()
57 {
58 HILOGI("BackupRestoreCallback destruct start");
59 if (!ctx_) {
60 HILOGE("BackupRestoreCallback ctx is nullptr");
61 return;
62 }
63
64 unique_ptr<LibN::NAsyncContextCallback> ptr(ctx_);
65 uv_loop_s *loop = nullptr;
66 napi_status status = napi_get_uv_event_loop(env_, &loop);
67 if (status != napi_ok) {
68 HILOGE("Failed to get uv event loop");
69 ptr->cb_.CleanJsEnv();
70 return;
71 }
72
73 auto work = make_unique<uv_work_t>();
74 if (work == nullptr) {
75 HILOGE("Failed to new uv_work_t");
76 return;
77 }
78 work->data = static_cast<void *>(ctx_);
79
80 auto task = [work {work.get()}]() {
81 if (work == nullptr) {
82 HILOGE("failed to get work.");
83 return;
84 }
85 LibN::NAsyncContextCallback *ctx = static_cast<LibN::NAsyncContextCallback *>(work->data);
86 HILOGI("BackupRestoreCallback destruct delete ctx");
87 delete ctx;
88 delete work;
89 };
90 auto ret = napi_send_event(env_, task, napi_eprio_high);
91 if (ret != napi_status::napi_ok) {
92 HILOGE("Failed to call napi_send_event, ret:%{public}d, status:%{public}d", ret, status);
93 return;
94 }
95 ptr.release();
96 work.release();
97 ctx_ = nullptr;
98 HILOGI("BackupRestoreCallback destruct end");
99 }
100
operator bool() const101 BackupRestoreCallback::operator bool() const
102 {
103 return bool(ctx_->cb_);
104 }
105
DoCallJsMethod(napi_env env,void * data,InputArgsParser argParser)106 static void DoCallJsMethod(napi_env env, void *data, InputArgsParser argParser)
107 {
108 HILOGI("Start execute DoCallJsMethod");
109 napi_handle_scope scope = nullptr;
110 napi_open_handle_scope(env, &scope);
111 if (scope == nullptr) {
112 HILOGE("scope is nullptr");
113 return;
114 }
115 auto ctx = static_cast<LibN::NAsyncContextCallback *>(data);
116 if (ctx == nullptr) {
117 HILOGE("This pointer address is empty");
118 napi_close_handle_scope(env, scope);
119 return;
120 }
121 vector<napi_value> argv = {};
122 if (argParser != nullptr) {
123 if (!argParser(env, argv)) {
124 HILOGE("failed to get params.");
125 napi_close_handle_scope(env, scope);
126 return;
127 }
128 }
129 napi_value global = nullptr;
130 napi_get_global(env, &global);
131 napi_value callback = ctx->cb_.Deref(env).val_;
132 if (!bool(ctx->cb_)) {
133 HILOGE("Failed to get ref.");
134 napi_close_handle_scope(env, scope);
135 return;
136 }
137 napi_value result = nullptr;
138 napi_status status = napi_call_function(env, global, callback, argv.size(), argv.data(), &result);
139 if (status != napi_ok) {
140 HILOGE("Failed to call function for %{public}d.", status);
141 }
142 napi_close_handle_scope(env, scope);
143 HILOGI("End execute DoCallJsMethod");
144 }
145
CallJsMethod(InputArgsParser argParser)146 void BackupRestoreCallback::CallJsMethod(InputArgsParser argParser)
147 {
148 HILOGI("call BackupRestoreCallback CallJsMethod begin.");
149 uv_loop_s *loop = nullptr;
150 napi_status status = napi_get_uv_event_loop(env_, &loop);
151 if (status != napi_ok) {
152 HILOGE("failed to get uv event loop.");
153 return;
154 }
155 auto workArgs = make_shared<WorkArgs>();
156 auto work = make_unique<uv_work_t>();
157 if (workArgs == nullptr || work == nullptr) {
158 HILOGE("failed to new workArgs or uv_work_t.");
159 return;
160 }
161 workArgs->ptr = this;
162 workArgs->argParser = argParser;
163 work->data = reinterpret_cast<void *>(workArgs.get());
164 HILOGI("Will execute current js method");
165 auto task = [work {work.get()}]() {
166 if (work == nullptr) {
167 HILOGE("failed to get work.");
168 return;
169 }
170 HILOGI("AsyncWork Enter, %{public}zu", (size_t)work);
171 auto workArgs = reinterpret_cast<WorkArgs *>(work->data);
172 do {
173 if (workArgs == nullptr) {
174 HILOGE("failed to get workArgs.");
175 break;
176 }
177 DoCallJsMethod(workArgs->ptr->env_, workArgs->ptr->ctx_, workArgs->argParser);
178 } while (false);
179 HILOGI("will notify current thread info");
180 std::unique_lock<std::mutex> lock(workArgs->callbackMutex);
181 workArgs->isReady.store(true);
182 workArgs->callbackCondition.notify_all();
183 delete work;
184 };
185 auto ret = napi_send_event(env_, task, napi_eprio_high);
186 if (ret != napi_status::napi_ok) {
187 HILOGE("failed to napi_send_event, ret:%{public}d.", ret);
188 work.reset();
189 return;
190 }
191 std::unique_lock<std::mutex> lock(workArgs->callbackMutex);
192 HILOGI("Wait execute callback method end");
193 workArgs->callbackCondition.wait(lock, [workArgs]() { return workArgs->isReady.load(); });
194 work.release();
195 HILOGI("call BackupRestoreCallback CallJsMethod end.");
196 }
197 } // namespace OHOS::FileManagement::Backup