• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2023 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 <thread>
16 
17 #include "ffrt/ffrt_utils.h"
18 #include "napi_pasteboard_common.h"
19 #include "pasteboard_app_event_dfx.h"
20 #include "pasteboard_hilog.h"
21 using namespace OHOS::MiscServices;
22 using namespace OHOS::Media;
23 
24 namespace OHOS {
25 namespace MiscServicesNapi {
26 static thread_local napi_ref g_systemPasteboard = nullptr;
27 static thread_local napi_ref g_systemPasteboard_instance = nullptr;
28 thread_local std::map<napi_ref, sptr<PasteboardObserverInstance>> SystemPasteboardNapi::observers_;
29 std::shared_ptr<PasteboardDelayGetterInstance> SystemPasteboardNapi::delayGetter_;
30 std::mutex SystemPasteboardNapi::delayMutex_;
31 constexpr int ARGC_TYPE_SET1 = 1;
32 constexpr size_t MAX_ARGS = 6;
33 constexpr size_t SYNC_TIMEOUT = 3500;
34 constexpr size_t DELAY_TIMEOUT = 2;
35 const std::string STRING_UPDATE = "update";
36 std::recursive_mutex SystemPasteboardNapi::listenerMutex_;
37 std::map<std::string, std::shared_ptr<ProgressListenerFn>> SystemPasteboardNapi::listenerMap_;
38 
PasteboardDelayGetterInstance(const napi_env & env,const napi_ref & ref)39 PasteboardDelayGetterInstance::PasteboardDelayGetterInstance(const napi_env &env, const napi_ref &ref)
40     : env_(env), ref_(ref)
41 {
42     stub_ = std::make_shared<PasteboardDelayGetterInstance::PasteboardDelayGetterImpl>();
43 }
44 
~PasteboardDelayGetterInstance()45 PasteboardDelayGetterInstance::~PasteboardDelayGetterInstance()
46 {
47     ref_ = nullptr;
48 }
49 
UvQueueWorkGetDelayPasteData(uv_work_t * work,int status)50 void UvQueueWorkGetDelayPasteData(uv_work_t *work, int status)
51 {
52     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "UvQueueWorkGetDelayPasteData start");
53     if (UV_ECANCELED == status || work == nullptr || work->data == nullptr) {
54         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parameter");
55         return;
56     }
57     PasteboardDelayWorker *pasteboardDelayWorker = (PasteboardDelayWorker *)work->data;
58     if (pasteboardDelayWorker == nullptr || pasteboardDelayWorker->delayGetter == nullptr) {
59         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker or delayGetter is null");
60         delete work;
61         work = nullptr;
62         return;
63     }
64     auto env = pasteboardDelayWorker->delayGetter->GetEnv();
65     auto ref = pasteboardDelayWorker->delayGetter->GetRef();
66     napi_handle_scope scope = nullptr;
67     napi_open_handle_scope(env, &scope);
68     if (scope == nullptr) {
69         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "scope is null");
70         return;
71     }
72     napi_value undefined = nullptr;
73     napi_get_undefined(env, &undefined);
74     napi_value argv[1] = { CreateNapiString(env, pasteboardDelayWorker->dataType) };
75     napi_value callback = nullptr;
76     napi_value resultOut = nullptr;
77     napi_get_reference_value(env, ref, &callback);
78     {
79         std::unique_lock<std::mutex> lock(pasteboardDelayWorker->mutex);
80         auto ret = napi_call_function(env, undefined, callback, 1, argv, &resultOut);
81         if (ret == napi_ok) {
82             PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "get delay data success");
83             UDMF::UnifiedDataNapi *unifiedDataNapi = nullptr;
84             napi_unwrap(env, resultOut, reinterpret_cast<void **>(&unifiedDataNapi));
85             if (unifiedDataNapi != nullptr) {
86                 pasteboardDelayWorker->unifiedData = unifiedDataNapi->value_;
87             }
88         }
89         napi_close_handle_scope(env, scope);
90         pasteboardDelayWorker->complete = true;
91         if (!pasteboardDelayWorker->clean) {
92             pasteboardDelayWorker->cv.notify_all();
93             return;
94         }
95     }
96     delete pasteboardDelayWorker;
97     pasteboardDelayWorker = nullptr;
98     delete work;
99     work = nullptr;
100 }
101 
ReleasePasteboardResource(PasteboardDelayWorker ** pasteboardDelayWorker,uv_work_t ** work)102 static void ReleasePasteboardResource(PasteboardDelayWorker **pasteboardDelayWorker, uv_work_t **work)
103 {
104     if (pasteboardDelayWorker == nullptr || work == nullptr ||
105         *pasteboardDelayWorker == nullptr || *work == nullptr) {
106         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parameter");
107         return;
108     }
109     delete *pasteboardDelayWorker;
110     *pasteboardDelayWorker = nullptr;
111     delete *work;
112     *work = nullptr;
113 }
114 
GetUnifiedData(const std::string & type,UDMF::UnifiedData & data)115 void PasteboardDelayGetterInstance::GetUnifiedData(const std::string &type, UDMF::UnifiedData &data)
116 {
117     uv_loop_s *loop = nullptr;
118     napi_get_uv_event_loop(env_, &loop);
119     if (loop == nullptr) {
120         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "loop instance is nullptr");
121         return;
122     }
123     uv_work_t *work = new (std::nothrow) uv_work_t;
124     if (work == nullptr) {
125         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "work is null");
126         return;
127     }
128     PasteboardDelayWorker *pasteboardDelayWorker = new (std::nothrow) PasteboardDelayWorker();
129     if (pasteboardDelayWorker == nullptr) {
130         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker is null");
131         delete work;
132         work = nullptr;
133         return;
134     }
135     pasteboardDelayWorker->delayGetter = shared_from_this();
136     pasteboardDelayWorker->dataType = type;
137     work->data = (void *)pasteboardDelayWorker;
138     bool noNeedClean = false;
139     {
140         std::unique_lock<std::mutex> lock(pasteboardDelayWorker->mutex);
141         int ret = uv_queue_work(loop, work, [](uv_work_t *work) {
142             PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData callback");
143         }, UvQueueWorkGetDelayPasteData);
144         if (ret != 0) {
145             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "uv_queue_work ret is not 0");
146             ReleasePasteboardResource(&pasteboardDelayWorker, &work);
147             return;
148         }
149         if (pasteboardDelayWorker->cv.wait_for(lock, std::chrono::seconds(DELAY_TIMEOUT),
150             [pasteboardDelayWorker] { return pasteboardDelayWorker->complete; }) &&
151             pasteboardDelayWorker->unifiedData != nullptr) {
152             data = *(pasteboardDelayWorker->unifiedData);
153         }
154         if (!pasteboardDelayWorker->complete && uv_cancel((uv_req_t*)work) != 0) {
155             pasteboardDelayWorker->clean = true;
156             noNeedClean = true;
157         }
158     }
159     if (!noNeedClean) {
160         ReleasePasteboardResource(&pasteboardDelayWorker, &work);
161     }
162 }
163 
CheckArgsOfOnAndOff(napi_env env,bool checkArgsCount,napi_value * argv,size_t argc)164 bool SystemPasteboardNapi::CheckArgsOfOnAndOff(napi_env env, bool checkArgsCount, napi_value *argv, size_t argc)
165 {
166     if (!CheckExpression(
167         env, checkArgsCount, JSErrorCode::INVALID_PARAMETERS, "Parameter error. The number of arguments is wrong.") ||
168         !CheckArgsType(env, argv[0], napi_string, "Parameter error. The type of mimeType must be string.")) {
169         return false;
170     }
171     std::string mimeType;
172     bool ret = GetValue(env, argv[0], mimeType);
173     if (!ret) {
174         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetValue failed");
175         return false;
176     }
177     if (!CheckExpression(env, mimeType == STRING_UPDATE, JSErrorCode::INVALID_PARAMETERS,
178         "Parameter error. The value of type must be update")) {
179         return false;
180     }
181     return true;
182 }
183 
On(napi_env env,napi_callback_info info)184 napi_value SystemPasteboardNapi::On(napi_env env, napi_callback_info info)
185 {
186     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi on() is called!");
187     napi_value result = nullptr;
188     napi_get_undefined(env, &result);
189 
190     size_t argc = MAX_ARGS;
191     napi_value argv[MAX_ARGS] = { 0 };
192     napi_value thisVar = 0;
193     void *data = nullptr;
194     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
195     // on(type: 'update', callback: () => void) has 2 args
196     if (!CheckArgsOfOnAndOff(env, argc >= 2, argv, argc) ||
197         !CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
198         return result;
199     }
200 
201     napi_value jsCallback = argv[1];
202     auto observer = GetObserver(env, jsCallback);
203     PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(observer == nullptr, result, PASTEBOARD_MODULE_JS_NAPI, "observer exist");
204 
205     AddObserver(env, jsCallback);
206     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi on() is end!");
207     return result;
208 }
209 
Off(napi_env env,napi_callback_info info)210 napi_value SystemPasteboardNapi::Off(napi_env env, napi_callback_info info)
211 {
212     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi off () is called!");
213     napi_value result = nullptr;
214     napi_get_undefined(env, &result);
215 
216     size_t argc = MAX_ARGS;
217     napi_value argv[MAX_ARGS] = { 0 };
218     napi_value thisVar = 0;
219     void *data = nullptr;
220     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
221     // off(type: 'update', callback?: () => void) has at least 1 arg
222     if (!CheckArgsOfOnAndOff(env, argc >= 1, argv, argc)) {
223         return result;
224     }
225 
226     sptr<PasteboardObserverInstance> observer = nullptr;
227     // 1: is the observer parameter
228     if (argc > 1) {
229         if (!CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
230             return result;
231         }
232         observer = GetObserver(env, argv[1]);
233         PASTEBOARD_CHECK_AND_RETURN_RET_LOGE(observer != nullptr, result,
234             PASTEBOARD_MODULE_JS_NAPI, "observer not find");
235     }
236 
237     DeleteObserver(env, observer);
238     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi off () is called!");
239     return result;
240 }
241 
Clear(napi_env env,napi_callback_info info)242 napi_value SystemPasteboardNapi::Clear(napi_env env, napi_callback_info info)
243 {
244     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Clear is called!");
245     auto context = std::make_shared<AsyncCall::Context>();
246     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
247         // clear has 0 or 1 args
248         if (argc > 0 &&
249             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
250             return napi_invalid_arg;
251         }
252         return napi_ok;
253     };
254     auto exec = [context](AsyncCall::Context *ctx) {
255         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec Clear");
256         PasteboardClient::GetInstance()->Clear();
257     };
258     context->SetAction(std::move(input));
259     // 0: the AsyncCall at the first position;
260     AsyncCall asyncCall(env, info, context, 0);
261     return asyncCall.Call(env, exec);
262 }
263 
ClearData(napi_env env,napi_callback_info info)264 napi_value SystemPasteboardNapi::ClearData(napi_env env, napi_callback_info info)
265 {
266     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "ClearData is called!");
267     return Clear(env, info);
268 }
269 
HasPasteData(napi_env env,napi_callback_info info)270 napi_value SystemPasteboardNapi::HasPasteData(napi_env env, napi_callback_info info)
271 {
272     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasPasteData is called!");
273     auto context = std::make_shared<HasContextInfo>();
274     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
275         // hasPasteData has 0 or 1 args
276         if (argc > 0 &&
277             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
278             return napi_invalid_arg;
279         }
280         return napi_ok;
281     };
282     auto output = [context](napi_env env, napi_value *result) -> napi_status {
283         napi_status status = napi_get_boolean(env, context->hasPasteData, result);
284         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "napi_get_boolean status = %{public}d", status);
285         return status;
286     };
287     auto exec = [context](AsyncCall::Context *ctx) {
288         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec HasPasteData");
289         context->hasPasteData = PasteboardClient::GetInstance()->HasPasteData();
290         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasPasteData result = %{public}d", context->hasPasteData);
291         context->status = napi_ok;
292     };
293     context->SetAction(std::move(input), std::move(output));
294     // 0: the AsyncCall at the first position;
295     AsyncCall asyncCall(env, info, context, 0);
296     return asyncCall.Call(env, exec);
297 }
298 
HasData(napi_env env,napi_callback_info info)299 napi_value SystemPasteboardNapi::HasData(napi_env env, napi_callback_info info)
300 {
301     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "HasData is called!");
302     return HasPasteData(env, info);
303 }
304 
GetDataCommon(std::shared_ptr<GetContextInfo> & context)305 void SystemPasteboardNapi::GetDataCommon(std::shared_ptr<GetContextInfo> &context)
306 {
307     auto input = [](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
308         // 1: GetPasteData has 0 or 1 args
309         if (argc > 0 &&
310             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
311             return napi_invalid_arg;
312         }
313         return napi_ok;
314     };
315 
316     auto output = [context](napi_env env, napi_value *result) -> napi_status {
317         napi_value instance = nullptr;
318         napi_status status = PasteDataNapi::NewInstance(env, instance);
319         if (status != napi_ok) {
320             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "NewInstance failed");
321             return status;
322         }
323         PasteDataNapi *obj = nullptr;
324         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
325         if ((ret == napi_ok) && (obj != nullptr)) {
326             obj->value_ = context->pasteData;
327         } else {
328             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "obj is null or ret not ok");
329             return napi_generic_failure;
330         }
331         *result = instance;
332         return napi_ok;
333     };
334     context->SetAction(std::move(input), std::move(output));
335 }
336 
GetPasteData(napi_env env,napi_callback_info info)337 napi_value SystemPasteboardNapi::GetPasteData(napi_env env, napi_callback_info info)
338 {
339     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData is called!");
340 
341     auto context = std::make_shared<GetContextInfo>();
342     context->pasteData = std::make_shared<PasteData>();
343     GetDataCommon(context);
344 
345     auto exec = [context](AsyncCall::Context *ctx) {
346         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData Begin");
347         PasteboardClient::GetInstance()->GetPasteData(*context->pasteData);
348         context->status = napi_ok;
349         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetPasteData End");
350     };
351 
352     // 0: the AsyncCall at the first position;
353     AsyncCall asyncCall(env, info, context, 0);
354     return asyncCall.Call(env, exec);
355 }
356 
GetData(napi_env env,napi_callback_info info)357 napi_value SystemPasteboardNapi::GetData(napi_env env, napi_callback_info info)
358 {
359     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData is called!");
360     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
361 
362     auto context = std::make_shared<GetContextInfo>();
363     context->pasteData = std::make_shared<PasteData>();
364     GetDataCommon(context);
365 
366     auto exec = [context, processorEvent](AsyncCall::Context *ctx) {
367         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData Begin");
368         int32_t ret = PasteboardClient::GetInstance()->GetPasteData(*context->pasteData);
369         if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
370             context->SetErrInfo(ret, "Another getData is being processed");
371         } else {
372             context->status = napi_ok;
373         }
374         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetData End");
375         PASTEBOARD_CHECK_AND_RETURN_LOGE(processorEvent != nullptr, PASTEBOARD_MODULE_JS_NAPI,
376             "processorEvent is null");
377         processorEvent->SetEvent("getData", ret, ret == static_cast<int32_t>(PasteboardError::E_OK) ?
378             EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
379     };
380     // 0: the AsyncCall at the first position;
381     AsyncCall asyncCall(env, info, context, 0);
382     return asyncCall.Call(env, exec);
383 }
384 
SetDataCommon(std::shared_ptr<SetContextInfo> & context)385 void SystemPasteboardNapi::SetDataCommon(std::shared_ptr<SetContextInfo> &context)
386 {
387     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
388         // setData has 1 or 2 args
389         if (!CheckExpression(
390             env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
391             "Parameter error. The number of arguments must be greater than zero.") ||
392             !CheckExpression(env, PasteDataNapi::IsPasteData(env, argv[0]), JSErrorCode::INVALID_PARAMETERS,
393             "Parameter error. The Type of data must be pasteData.")) {
394             return napi_invalid_arg;
395         }
396         if (argc > 1 &&
397             !CheckArgsType(env, argv[1], napi_function, "Parameter error. The type of callback must be function.")) {
398             return napi_invalid_arg;
399         }
400         PasteDataNapi *pasteData = nullptr;
401         napi_unwrap(env, argv[0], reinterpret_cast<void **>(&pasteData));
402         if (pasteData != nullptr) {
403             context->obj = pasteData->value_;
404         }
405         return napi_ok;
406     };
407     context->SetAction(std::move(input));
408 }
409 
SetPasteData(napi_env env,napi_callback_info info)410 napi_value SystemPasteboardNapi::SetPasteData(napi_env env, napi_callback_info info)
411 {
412     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetPasteData is called!");
413     auto context = std::make_shared<SetContextInfo>();
414     SetDataCommon(context);
415 
416     auto exec = [context](AsyncCall::Context *ctx) {
417         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
418         if (context->obj != nullptr) {
419             PasteboardClient::GetInstance()->SetPasteData(*(context->obj));
420             context->obj = nullptr;
421         }
422         context->status = napi_ok;
423     };
424     // 1: the AsyncCall at the second position
425     AsyncCall asyncCall(env, info, context, 1);
426     return asyncCall.Call(env, exec);
427 }
428 
SetData(napi_env env,napi_callback_info info)429 napi_value SystemPasteboardNapi::SetData(napi_env env, napi_callback_info info)
430 {
431     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetData is called!");
432     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
433     auto context = std::make_shared<SetContextInfo>();
434     SetDataCommon(context);
435 
436     auto exec = [context, processorEvent](AsyncCall::Context *ctx) {
437         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
438         int32_t ret = static_cast<int32_t>(PasteboardError::INVALID_DATA_ERROR);
439         if (context->obj != nullptr) {
440             std::map<uint32_t, std::shared_ptr<UDMF::EntryGetter>> entryGetters;
441             for (auto record : context->obj->AllRecords()) {
442                 if (record != nullptr && record->GetEntryGetter() != nullptr) {
443                     entryGetters.emplace(record->GetRecordId(), record->GetEntryGetter());
444                 }
445             }
446             ret = PasteboardClient::GetInstance()->SetPasteData(*(context->obj), nullptr, entryGetters);
447             context->obj = nullptr;
448         }
449         if (ret == static_cast<int32_t>(PasteboardError::E_OK)) {
450             context->status = napi_ok;
451         } else if (ret == static_cast<int32_t>(PasteboardError::PROHIBIT_COPY)) {
452             context->SetErrInfo(ret, "The system prohibits copying");
453         } else if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
454             context->SetErrInfo(ret, "Another setData is being processed");
455         }
456         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec context->status[%{public}d]", context->status);
457         PASTEBOARD_CHECK_AND_RETURN_LOGE(processorEvent != nullptr, PASTEBOARD_MODULE_JS_NAPI,
458             "processorEvent is null");
459         processorEvent->SetEvent("setData", ret, ret == static_cast<int32_t>(PasteboardError::E_OK) ?
460             EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
461     };
462     // 1: the AsyncCall at the second position
463     AsyncCall asyncCall(env, info, context, 1);
464     return asyncCall.Call(env, exec);
465 }
466 
SetUnifiedData(napi_env env,napi_callback_info info)467 napi_value SystemPasteboardNapi::SetUnifiedData(napi_env env, napi_callback_info info)
468 {
469     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SetUnifiedData is called!");
470     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
471     auto context = std::make_shared<SetUnifiedContextInfo>();
472     SetDataCommon(context);
473 
474     auto exec = [context, processorEvent](AsyncCall::Context* ctx) {
475         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec SetPasteData");
476         int32_t ret = static_cast<int32_t>(PasteboardError::INVALID_DATA_ERROR);
477         if (context->obj != nullptr) {
478             if (context->isDelay && context->delayGetter != nullptr && context->delayGetter->GetStub() != nullptr) {
479                 ret = PasteboardClient::GetInstance()->SetUnifiedData(*(context->obj), context->delayGetter->GetStub());
480             } else {
481                 ret = PasteboardClient::GetInstance()->SetUnifiedData(*(context->obj));
482             }
483             context->obj = nullptr;
484         }
485         if (ret == static_cast<int32_t>(PasteboardError::E_OK)) {
486             context->status = napi_ok;
487         } else if (ret == static_cast<int32_t>(PasteboardError::PROHIBIT_COPY)) {
488             context->SetErrInfo(ret, "The system prohibits copying");
489         } else if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
490             context->SetErrInfo(ret, "Another setData is being processed");
491         }
492         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "exec context->status[%{public}d]", context->status);
493         PASTEBOARD_CHECK_AND_RETURN_LOGE(processorEvent != nullptr, PASTEBOARD_MODULE_JS_NAPI,
494             "processorEvent is null");
495         processorEvent->SetEvent("setUnifiedData", ret, ret == static_cast<int32_t>(PasteboardError::E_OK) ?
496             EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
497     };
498     // 1: the AsyncCall at the second position
499     AsyncCall asyncCall(env, info, context, 1);
500     return asyncCall.Call(env, exec);
501 }
502 
GetUnifiedData(napi_env env,napi_callback_info info)503 napi_value SystemPasteboardNapi::GetUnifiedData(napi_env env, napi_callback_info info)
504 {
505     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData is called!");
506     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
507 
508     auto context = std::make_shared<GetUnifiedContextInfo>();
509     context->unifiedData = std::make_shared<UDMF::UnifiedData>();
510     GetDataCommon(context);
511 
512     auto exec = [context, processorEvent](AsyncCall::Context* ctx) {
513         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData Begin");
514         int32_t ret = PasteboardClient::GetInstance()->GetUnifiedData(*context->unifiedData);
515         if (ret == static_cast<int32_t>(PasteboardError::TASK_PROCESSING)) {
516             context->SetErrInfo(ret, "Another getData is being processed");
517         } else {
518             context->status = napi_ok;
519         }
520         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedData End");
521         PASTEBOARD_CHECK_AND_RETURN_LOGE(processorEvent != nullptr, PASTEBOARD_MODULE_JS_NAPI,
522             "processorEvent is null");
523         processorEvent->SetEvent("getUnifiedData", ret, ret == static_cast<int32_t>(PasteboardError::E_OK) ?
524             EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
525     };
526     // 0: the AsyncCall at the first position;
527     AsyncCall asyncCall(env, info, context, 0);
528     return asyncCall.Call(env, exec);
529 }
530 
GetUnifiedDataSync(napi_env env,napi_callback_info info)531 napi_value SystemPasteboardNapi::GetUnifiedDataSync(napi_env env, napi_callback_info info)
532 {
533     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetUnifiedDataSync is called!");
534     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
535     napi_value instance = nullptr;
536     std::shared_ptr<UDMF::UnifiedData> unifiedData = std::make_shared<UDMF::UnifiedData>();
537 
538     NAPI_CALL(env, UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, instance));
539     UDMF::UnifiedDataNapi* obj = nullptr;
540     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void**>(&obj));
541     if ((status != napi_ok) || (obj == nullptr) || obj->value_ == nullptr) {
542         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetUnifiedDataSync get obj failed.");
543         processorEvent->SetEvent("getUnifiedDataSync", static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS),
544             EventReportResult::EVENT_REPORT_FAIL);
545         return nullptr;
546     }
547     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
548     std::thread thread([block, unifiedData = obj->value_]() mutable {
549         auto ret = PasteboardClient::GetInstance()->GetUnifiedData(*unifiedData);
550         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
551         block->SetValue(value);
552     });
553     thread.detach();
554     auto value = block->GetValue();
555     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
556                          "Excessive processing time for internal data.")) {
557         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetUnifiedDataSync failed.");
558     }
559     int32_t ret = (value != nullptr) ? *value : static_cast<int32_t>(PasteboardError::TIMEOUT_ERROR);
560     processorEvent->SetEvent("getUnifiedDataSync", ret, ret == static_cast<int32_t>(PasteboardError::E_OK) ?
561         EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
562     return instance;
563 }
564 
SetUnifiedDataSync(napi_env env,napi_callback_info info)565 napi_value SystemPasteboardNapi::SetUnifiedDataSync(napi_env env, napi_callback_info info)
566 {
567     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi SetUnifiedDataSync is called!");
568     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
569     size_t argc = ARGC_TYPE_SET1;
570     napi_value argv[ARGC_TYPE_SET1] = {0};
571     napi_value thisVar = nullptr;
572 
573     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
574     if (!CheckExpression(
575         env, argc > 0, JSErrorCode::INVALID_PARAMETERS, "Parameter error. Wrong number of arguments.")) {
576         processorEvent->SetEvent("setUnifiedDataSync", static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS),
577             EventReportResult::EVENT_REPORT_FAIL);
578         return nullptr;
579     }
580     UDMF::UnifiedDataNapi* unifiedDataNapi = nullptr;
581     napi_unwrap(env, argv[0], reinterpret_cast<void**>(&unifiedDataNapi));
582     if (!CheckExpression(env, (unifiedDataNapi != nullptr && unifiedDataNapi->value_ != nullptr),
583         JSErrorCode::INVALID_PARAMETERS, "Parameter error. The Type of data must be unifiedData.")) {
584         processorEvent->SetEvent("setUnifiedDataSync", static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS),
585             EventReportResult::EVENT_REPORT_FAIL);
586         return nullptr;
587     }
588     auto properties = unifiedDataNapi->GetPropertiesNapi(env);
589     bool isDelay = false;
590     std::shared_ptr<PasteboardDelayGetterInstance> delayGetter = nullptr;
591     if (properties != nullptr && properties->delayDataRef_ != nullptr) {
592         delayGetter = std::make_shared<PasteboardDelayGetterInstance>(env, properties->delayDataRef_);
593         delayGetter->GetStub()->SetDelayGetterWrapper(delayGetter);
594         isDelay = true;
595     }
596     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
597     std::shared_ptr<UDMF::UnifiedData> unifiedData = unifiedDataNapi->value_;
598     std::thread thread([block, unifiedData, isDelay, delayGetter]() mutable {
599         int32_t ret = isDelay ?
600             PasteboardClient::GetInstance()->SetUnifiedData(*unifiedData, delayGetter->GetStub()) :
601             PasteboardClient::GetInstance()->SetUnifiedData(*unifiedData);
602         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
603         block->SetValue(value);
604     });
605     thread.detach();
606     auto value = block->GetValue();
607     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
608                          "Excessive processing time for internal data.")) {
609         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, SetUnifiedDataSync failed.");
610         processorEvent->SetEvent("setUnifiedDataSync", static_cast<int32_t>(JSErrorCode::REQUEST_TIME_OUT),
611             EventReportResult::EVENT_REPORT_FAIL);
612         return nullptr;
613     }
614     if (*value != static_cast<int32_t>(PasteboardError::E_OK)) {
615         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "operate invalid, SetUnifiedDataSync failed");
616         processorEvent->SetEvent("setUnifiedDataSync", *value, *value == static_cast<int32_t>(PasteboardError::E_OK) ?
617             EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
618         return nullptr;
619     }
620     {
621         std::lock_guard<std::mutex> lck(delayMutex_);
622         delayGetter_ = delayGetter;
623     }
624     processorEvent->SetEvent("setUnifiedDataSync", *value, *value == static_cast<int32_t>(PasteboardError::E_OK) ?
625         EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
626     return nullptr;
627 }
628 
SetAppShareOptions(napi_env env,napi_callback_info info)629 napi_value SystemPasteboardNapi::SetAppShareOptions(napi_env env, napi_callback_info info)
630 {
631     size_t argc = ARGC_TYPE_SET1;
632     napi_value argv[ARGC_TYPE_SET1] = {0};
633     napi_value thisArg = nullptr;
634     void *data = nullptr;
635     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data));
636     if (!CheckExpression(env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
637         "Parameter error. Mandatory parameters are left unspecified.")) {
638         return nullptr;
639     }
640     int32_t shareOptions;
641     auto status = napi_get_value_int32(env, argv[0], &shareOptions);
642     if (!CheckExpression(env, status == napi_ok, JSErrorCode::INVALID_PARAMETERS,
643         "Parameter error. Incorrect parameter types.")) {
644         return nullptr;
645     }
646     auto result = PasteboardClient::GetInstance()->SetAppShareOptions(static_cast<ShareOption>(shareOptions));
647     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::INVALID_PARAM_ERROR),
648         JSErrorCode::INVALID_PARAMETERS, "Parameter error. Parameter verification failed.")) {
649         return nullptr;
650     }
651     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::PERMISSION_VERIFICATION_ERROR),
652         JSErrorCode::NO_PERMISSION,
653         "Permission verification failed. A non-permission application calls a API.")) {
654         return nullptr;
655     }
656     if (!CheckExpression(env, result != static_cast<int32_t>(PasteboardError::INVALID_OPERATION_ERROR),
657         JSErrorCode::SETTINGS_ALREADY_EXIST, "Settings already exist.")) {
658         return nullptr;
659     }
660     return nullptr;
661 }
662 
RemoveAppShareOptions(napi_env env,napi_callback_info info)663 napi_value SystemPasteboardNapi::RemoveAppShareOptions(napi_env env, napi_callback_info info)
664 {
665     auto result = PasteboardClient::GetInstance()->RemoveAppShareOptions();
666     CheckExpression(env, result != static_cast<int32_t>(PasteboardError::PERMISSION_VERIFICATION_ERROR),
667         JSErrorCode::NO_PERMISSION,
668         "Permission verification failed. A non-permission application calls a API.");
669     return nullptr;
670 }
671 
SetDataCommon(std::shared_ptr<SetUnifiedContextInfo> & context)672 void SystemPasteboardNapi::SetDataCommon(std::shared_ptr<SetUnifiedContextInfo>& context)
673 {
674     auto input = [context](napi_env env, size_t argc, napi_value* argv, napi_value self) -> napi_status {
675         // setData has 1 arg
676         if (!CheckExpression(
677             env, argc > 0, JSErrorCode::INVALID_PARAMETERS, "Parameter error. Wrong number of arguments.")) {
678             return napi_invalid_arg;
679         }
680         UDMF::UnifiedDataNapi* unifiedDataNapi = nullptr;
681         context->status = napi_unwrap(env, argv[0], reinterpret_cast<void**>(&unifiedDataNapi));
682         if (!CheckExpression(env, unifiedDataNapi != nullptr,
683             JSErrorCode::INVALID_PARAMETERS, "Parameter error. The Type of data must be unifiedData.")) {
684             return napi_invalid_arg;
685         }
686         context->obj = unifiedDataNapi->value_;
687         auto properties = unifiedDataNapi->GetPropertiesNapi(env);
688         if (properties != nullptr && properties->delayDataRef_ != nullptr) {
689             context->delayGetter = std::make_shared<PasteboardDelayGetterInstance>(env, properties->delayDataRef_);
690             if (context->delayGetter == nullptr || context->delayGetter->GetStub() == nullptr) {
691                 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "SetDataCommon delayGetter is null");
692                 return napi_invalid_arg;
693             }
694             context->delayGetter->GetStub()->SetDelayGetterWrapper(context->delayGetter);
695             context->isDelay = true;
696         }
697         return napi_ok;
698     };
699     auto output = [context](napi_env env, napi_value *result) -> napi_status {
700         if (context->status == napi_ok) {
701             std::lock_guard<std::mutex> lck(delayMutex_);
702             delayGetter_ = std::move(context->delayGetter);
703         }
704         return napi_ok;
705     };
706     context->SetAction(std::move(input), std::move(output));
707 }
708 
GetDataCommon(std::shared_ptr<GetUnifiedContextInfo> & context)709 void SystemPasteboardNapi::GetDataCommon(std::shared_ptr<GetUnifiedContextInfo>& context)
710 {
711     auto input = [](napi_env env, size_t argc, napi_value* argv, napi_value self) -> napi_status {
712         // 1: GetPasteData has 0 or 1 args
713         if (argc > 0 &&
714             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
715             return napi_invalid_arg;
716         }
717         return napi_ok;
718     };
719 
720     auto output = [context](napi_env env, napi_value* result) -> napi_status {
721         napi_value instance = nullptr;
722         std::shared_ptr<UDMF::UnifiedData> unifiedData = std::make_shared<UDMF::UnifiedData>();
723         napi_status status = UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, instance);
724         if (status != napi_ok) {
725             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "NewInstance failed");
726             return status;
727         }
728 
729         UDMF::UnifiedDataNapi* obj = nullptr;
730         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void**>(&obj));
731         if ((ret == napi_ok) && (obj != nullptr)) {
732             obj->value_ = context->unifiedData;
733         } else {
734             return napi_generic_failure;
735         }
736         *result = instance;
737         return napi_ok;
738     };
739     context->SetAction(std::move(input), std::move(output));
740 }
741 
IsRemoteData(napi_env env,napi_callback_info info)742 napi_value SystemPasteboardNapi::IsRemoteData(napi_env env, napi_callback_info info)
743 {
744     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi IsRemoteData() is called!");
745     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
746     std::thread thread([block]() {
747         auto ret = PasteboardClient::GetInstance()->IsRemoteData();
748         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value=%{public}d", ret);
749         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(static_cast<int32_t>(ret));
750         block->SetValue(value);
751     });
752     thread.detach();
753     auto value = block->GetValue();
754     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
755                          "Excessive processing time for internal data.")) {
756         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, IsRemoteData failed.");
757         return nullptr;
758     }
759     napi_value result = nullptr;
760     napi_get_boolean(env, *value, &result);
761     return result;
762 }
763 
GetDataSource(napi_env env,napi_callback_info info)764 napi_value SystemPasteboardNapi::GetDataSource(napi_env env, napi_callback_info info)
765 {
766     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetDataSource() is called!");
767     std::string bundleName;
768     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
769     std::thread thread([block, &bundleName]() mutable {
770         auto ret = PasteboardClient::GetInstance()->GetDataSource(bundleName);
771         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
772         block->SetValue(value);
773     });
774     thread.detach();
775     auto value = block->GetValue();
776     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
777                          "Excessive processing time for internal data.")) {
778         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetDataSource failed.");
779         return nullptr;
780     }
781 
782     if (*value != static_cast<int32_t>(PasteboardError::E_OK)) {
783         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetDataSource, failed, ret = %{public}d", *value);
784         return nullptr;
785     }
786     napi_value result = nullptr;
787     napi_create_string_utf8(env, bundleName.c_str(), NAPI_AUTO_LENGTH, &result);
788     return result;
789 }
790 
GetMimeTypes(napi_env env,napi_callback_info info)791 napi_value SystemPasteboardNapi::GetMimeTypes(napi_env env, napi_callback_info info)
792 {
793     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetMimeTypes() is called!");
794     auto context = std::make_shared<GetMimeTypesContextInfo>();
795     auto input = [](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
796         if (argc > 0 &&
797             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
798             return napi_invalid_arg;
799         }
800         return napi_ok;
801     };
802     auto output = [context](napi_env env, napi_value *result) -> napi_status {
803         napi_status status = NapiDataUtils::SetValue(env, context->mimeTypes, *result);
804         return status;
805     };
806     auto exec = [context](AsyncCall::Context *ctx) {
807         context->mimeTypes = PasteboardClient::GetInstance()->GetMimeTypes();
808         context->status = napi_ok;
809     };
810     context->SetAction(std::move(input), std::move(output));
811     AsyncCall asyncCall(env, info, context, 1);
812     return asyncCall.Call(env, exec);
813 }
814 
GetChangeCount(napi_env env,napi_callback_info info)815 napi_value SystemPasteboardNapi::GetChangeCount(napi_env env, napi_callback_info info)
816 {
817     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetChangeCount() is called!");
818     uint32_t changeCount = 0;
819     PasteboardClient::GetInstance()->GetChangeCount(changeCount);
820     napi_value result = nullptr;
821     napi_create_uint32(env, changeCount, &result);
822     return result;
823 }
824 
HasDataType(napi_env env,napi_callback_info info)825 napi_value SystemPasteboardNapi::HasDataType(napi_env env, napi_callback_info info)
826 {
827     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi HasDataType() is called!");
828     size_t argc = ARGC_TYPE_SET1;
829     napi_value argv[ARGC_TYPE_SET1] = {0};
830     napi_value thisVar = nullptr;
831 
832     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
833     if ((!CheckExpression(env, argc >= ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
834         "Parameter error. The number of arguments must be grater than zero.")) ||
835         (!CheckArgsType(env, argv[0], napi_string, "Parameter error. The type of mimeType must be string."))) {
836         return nullptr;
837     }
838 
839     std::string mimeType;
840     if (!GetValue(env, argv[0], mimeType)) {
841         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue!");
842         return nullptr;
843     }
844     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
845     ffrt::submit([block, mimeType]() {
846         auto ret = PasteboardClient::GetInstance()->HasDataType(mimeType);
847         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "ret = %{public}d", ret);
848         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(static_cast<int32_t>(ret));
849         block->SetValue(value);
850         }, {}, {}, ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_user_interactive)));
851     auto value = block->GetValue();
852     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
853                          "Excessive processing time for internal data.")) {
854         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, HasDataType failed.");
855         return nullptr;
856     }
857     napi_value result = nullptr;
858     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value = %{public}d", *value);
859     napi_get_boolean(env, *value, &result);
860     return result;
861 }
862 
DetectPatterns(napi_env env,napi_callback_info info)863 napi_value SystemPasteboardNapi::DetectPatterns(napi_env env, napi_callback_info info)
864 {
865     auto context = std::make_shared<DetectPatternsContextInfo>();
866     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
867         if (!CheckExpression(env, argc == ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
868             "Parameter error. The number of arguments must be one.")) {
869             return napi_invalid_arg;
870         }
871         bool getValueRes = GetValue(env, argv[0], context->patternsToCheck);
872         if (!CheckExpression(env, getValueRes, JSErrorCode::INVALID_PARAMETERS,
873             "Parameter error. Array<Pattern> expected.")) {
874             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue.");
875             return napi_invalid_arg;
876         }
877         return napi_ok;
878     };
879     auto output = [context](napi_env env, napi_value *result) -> napi_status {
880         napi_status status = SetValue(env, context->patternsDetect, *result);
881         return status;
882     };
883     auto exec = [context](AsyncCall::Context *ctx) {
884         context->patternsDetect = PasteboardClient::GetInstance()->DetectPatterns(context->patternsToCheck);
885         context->status = napi_ok;
886     };
887     context->SetAction(std::move(input), std::move(output));
888     AsyncCall asyncCall(env, info, context, 1);
889     return asyncCall.Call(env, exec);
890 }
891 
ClearDataSync(napi_env env,napi_callback_info info)892 napi_value SystemPasteboardNapi::ClearDataSync(napi_env env, napi_callback_info info)
893 {
894     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi ClearDataSync() is called!");
895     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
896     std::thread thread([block]() {
897         PasteboardClient::GetInstance()->Clear();
898         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(0);
899         block->SetValue(value);
900     });
901     thread.detach();
902     auto value = block->GetValue();
903     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
904                          "Excessive processing time for internal data.")) {
905         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, ClearDataSync failed.");
906     }
907     return nullptr;
908 }
909 
GetDataSync(napi_env env,napi_callback_info info)910 napi_value SystemPasteboardNapi::GetDataSync(napi_env env, napi_callback_info info)
911 {
912     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi GetDataSync() is called!");
913     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
914     napi_value instance = nullptr;
915     NAPI_CALL(env, PasteDataNapi::NewInstance(env, instance));
916     PasteDataNapi *obj = nullptr;
917     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
918     if ((status != napi_ok) || (obj == nullptr) || obj->value_ == nullptr) {
919         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetDataSync napi_unwrap failed");
920         processorEvent->SetEvent("getDataSync", static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS),
921             EventReportResult::EVENT_REPORT_FAIL);
922         return nullptr;
923     }
924     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
925     std::thread thread([block, pasteData = obj->value_]() mutable {
926         auto ret = PasteboardClient::GetInstance()->GetPasteData(*pasteData);
927         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
928         block->SetValue(value);
929     });
930     thread.detach();
931     auto value = block->GetValue();
932     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
933                          "Excessive processing time for internal data.")) {
934         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, GetDataSync failed.");
935     }
936     int32_t ret = (value != nullptr) ? *value : static_cast<int32_t>(PasteboardError::TIMEOUT_ERROR);
937     processorEvent->SetEvent("getDataSync", ret, ret == static_cast<int32_t>(PasteboardError::E_OK) ?
938         EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
939     return instance;
940 }
941 
SetDataSync(napi_env env,napi_callback_info info)942 napi_value SystemPasteboardNapi::SetDataSync(napi_env env, napi_callback_info info)
943 {
944     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi SetDataSync() is called!");
945     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
946     size_t argc = ARGC_TYPE_SET1;
947     napi_value argv[ARGC_TYPE_SET1] = {0};
948     napi_value thisVar = nullptr;
949 
950     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
951     if (!CheckExpression(env, argc > 0, JSErrorCode::INVALID_PARAMETERS,
952         "Parameter error. The number of arguments must be one.") ||
953         !CheckExpression(env, PasteDataNapi::IsPasteData(env, argv[0]), JSErrorCode::INVALID_PARAMETERS,
954         "Parameter error. The Type of data must be pasteData.")) {
955         processorEvent->SetEvent("setDataSync", static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS),
956             EventReportResult::EVENT_REPORT_FAIL);
957         return nullptr;
958     }
959 
960     PasteDataNapi *pasteData = nullptr;
961     napi_unwrap(env, argv[0], reinterpret_cast<void **>(&pasteData));
962     if (pasteData == nullptr || pasteData->value_ == nullptr) {
963         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to GetValue!");
964         processorEvent->SetEvent("setDataSync", static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS),
965             EventReportResult::EVENT_REPORT_FAIL);
966         return nullptr;
967     }
968     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
969     std::shared_ptr<PasteData> data = pasteData->value_;
970     std::thread thread([block, data]() {
971         auto ret = PasteboardClient::GetInstance()->SetPasteData(*data);
972         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(ret);
973         block->SetValue(value);
974     });
975     thread.detach();
976     auto value = block->GetValue();
977     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
978                          "Excessive processing time for internal data.")) {
979         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, SetDataSync failed.");
980         processorEvent->SetEvent("setDataSync", static_cast<int32_t>(JSErrorCode::REQUEST_TIME_OUT),
981             EventReportResult::EVENT_REPORT_FAIL);
982         return nullptr;
983     }
984 
985     if (*value != static_cast<int32_t>(PasteboardError::E_OK)) {
986         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "operate invalid, SetDataSync failed");
987         processorEvent->SetEvent("setDataSync", *value, EventReportResult::EVENT_REPORT_FAIL);
988         return nullptr;
989     }
990     processorEvent->SetEvent("setDataSync", *value, EventReportResult::EVENT_REPORT_SUCCESS);
991     return nullptr;
992 }
993 
HasDataSync(napi_env env,napi_callback_info info)994 napi_value SystemPasteboardNapi::HasDataSync(napi_env env, napi_callback_info info)
995 {
996     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "SystemPasteboardNapi HasDataSync() is called!");
997     auto block = std::make_shared<BlockObject<std::shared_ptr<int32_t>>>(SYNC_TIMEOUT);
998     std::thread thread([block]() {
999         auto ret = PasteboardClient::GetInstance()->HasPasteData();
1000         std::shared_ptr<int32_t> value = std::make_shared<int32_t>(static_cast<int32_t>(ret));
1001         block->SetValue(value);
1002     });
1003     thread.detach();
1004     auto value = block->GetValue();
1005     if (!CheckExpression(env, value != nullptr, JSErrorCode::REQUEST_TIME_OUT,
1006                          "Excessive processing time for internal data.")) {
1007         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "time out, HasDataSync failed.");
1008         return nullptr;
1009     }
1010     napi_value result = nullptr;
1011     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "value=%{public}d", *value);
1012     napi_get_boolean(env, *value, &result);
1013     return result;
1014 }
1015 
ProgressNotify(std::shared_ptr<GetDataParams> params)1016 void SystemPasteboardNapi::ProgressNotify(std::shared_ptr<GetDataParams> params)
1017 {
1018     if (params == nullptr) {
1019         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "params is null!");
1020         return;
1021     }
1022 
1023     if (params->info == nullptr) {
1024         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "params->info is null!");
1025         return;
1026     }
1027     std::shared_ptr<ProgressListenerFn> listenerFn = nullptr;
1028     std::lock_guard<std::recursive_mutex> lock(listenerMutex_);
1029     auto it = listenerMap_.find("progressNotify");
1030     if (it != listenerMap_.end()) {
1031         listenerFn = it->second;
1032     }
1033 
1034     if (listenerFn == nullptr || listenerFn->tsFunction == nullptr) {
1035         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "thread safe function is nullptr!");
1036         return;
1037     }
1038 
1039     napi_status status = napi_acquire_threadsafe_function(listenerFn->tsFunction);
1040     if (status != napi_ok) {
1041         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "acquire progressNotify failed!");
1042         return;
1043     }
1044 
1045     MiscServices::ProgressInfo *progress = new ProgressInfo();
1046     progress->percentage = params->info->percentage;
1047     status = napi_call_threadsafe_function(listenerFn->tsFunction, static_cast<void *>(progress), napi_tsfn_blocking);
1048     if (status != napi_ok) {
1049         delete progress;
1050         progress = nullptr;
1051         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "call progressNotify failed!");
1052         return;
1053     }
1054 
1055     status = napi_release_threadsafe_function(listenerFn->tsFunction, napi_tsfn_release);
1056     if (status != napi_ok) {
1057         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "release progressNotify failed!");
1058         return;
1059     }
1060 }
1061 
CallJsProgressNotify(napi_env env,napi_value jsFunction,void * context,void * data)1062 void SystemPasteboardNapi::CallJsProgressNotify(napi_env env, napi_value jsFunction, void *context, void *data)
1063 {
1064     #define AGR_COUNT 1
1065     #define DEVICE_NAME_LEN 512
1066     (void)context;
1067     ProgressInfo *info = (ProgressInfo *)data;
1068     if (info == nullptr) {
1069         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "progressInfo is nullptr!");
1070         return;
1071     }
1072 
1073     int progress = info->percentage;
1074     delete info;
1075     info = nullptr;
1076 
1077     napi_value percentage;
1078     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, progress, &percentage));
1079 
1080     napi_value progressInfo = nullptr;
1081     NAPI_CALL_RETURN_VOID(env, napi_create_object(env, &progressInfo));
1082     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, progressInfo, "progress", percentage));
1083 
1084     napi_value argv[AGR_COUNT] = { progressInfo };
1085     NAPI_CALL_RETURN_VOID(env, napi_call_function(env, NULL, jsFunction, AGR_COUNT, argv, NULL));
1086 }
1087 
CreateThreadSafeFunc(napi_env env,const std::shared_ptr<ProgressListenerFn> listenerFn)1088 bool SystemPasteboardNapi::CreateThreadSafeFunc(napi_env env, const std::shared_ptr<ProgressListenerFn> listenerFn)
1089 {
1090     #define MAX_LISTENER_LEN 20
1091     napi_value name = nullptr;
1092     if (listenerFn->jsCallback == nullptr) {
1093         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "jsCallback is null!");
1094         return false;
1095     }
1096 
1097     NAPI_CALL_BASE(env, napi_create_string_utf8(env, "progressNotify", MAX_LISTENER_LEN, &name), false);
1098     napi_status status = napi_create_threadsafe_function(env, listenerFn->jsCallback, NULL, name, 0, 1, NULL,
1099         NULL, NULL, CallJsProgressNotify, &listenerFn->tsFunction);
1100     if (status != napi_ok) {
1101         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "create threadsafe failed!");
1102         return false;
1103     }
1104     return true;
1105 }
1106 
AddProgressListener(napi_env env,std::shared_ptr<MiscServices::GetDataParams> getDataParam,const std::shared_ptr<ProgressListenerFn> listenerFn)1107 bool SystemPasteboardNapi::AddProgressListener(napi_env env, std::shared_ptr<MiscServices::GetDataParams> getDataParam,
1108     const std::shared_ptr<ProgressListenerFn> listenerFn)
1109 {
1110     std::lock_guard<std::recursive_mutex> lock(listenerMutex_);
1111     auto it = listenerMap_.find("progressNotify");
1112     if (it == listenerMap_.end()) {
1113         listenerMap_.insert({ "progressNotify", listenerFn });
1114     }
1115 
1116     if (!CreateThreadSafeFunc(env, listenerFn)) {
1117         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "CreateThreadSafeFunc failed!");
1118         listenerMap_.erase("progressNotify");
1119         return false;
1120     }
1121 
1122     getDataParam->listener.ProgressNotify = ProgressNotify;
1123     return true;
1124 }
1125 
CheckParamsType(napi_env env,napi_value in,napi_valuetype expectedType)1126 bool SystemPasteboardNapi::CheckParamsType(napi_env env, napi_value in, napi_valuetype expectedType)
1127 {
1128     napi_valuetype type = napi_undefined;
1129     NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false);
1130     if (type != expectedType) {
1131         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "invalid parameters!");
1132         return false;
1133     }
1134     return true;
1135 }
1136 
ParseJsGetDataWithProgress(napi_env env,napi_value in,std::shared_ptr<MiscServices::GetDataParams> & getDataParam)1137 bool SystemPasteboardNapi::ParseJsGetDataWithProgress(napi_env env, napi_value in,
1138     std::shared_ptr<MiscServices::GetDataParams> &getDataParam)
1139 {
1140     #define MAX_DESTURI_LEN 250
1141     napi_value destUri = nullptr;
1142     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "destUri", &destUri), false);
1143     if (CheckParamsType(env, destUri, napi_string)) {
1144         size_t destUriLen = 0;
1145         NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, destUri, nullptr, 0, &destUriLen), false);
1146         if (destUriLen <= 0 || destUriLen > MAX_DESTURI_LEN) {
1147             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "destUriLen check failed!");
1148             return false;
1149         }
1150         char *uri = (char *)malloc(destUriLen + 1);
1151         if (uri == nullptr) {
1152             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "malloc failed, uri is nullptr.");
1153             return false;
1154         }
1155         NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, destUri, uri, destUriLen + 1, &destUriLen), false);
1156         getDataParam->destUri = uri;
1157         free(uri);
1158     }
1159     napi_value fileConflictOption;
1160     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "fileConflictOptions", &fileConflictOption), false);
1161     getDataParam->fileConflictOption = FILE_OVERWRITE;
1162     if (CheckParamsType(env, fileConflictOption, napi_number)) {
1163         NAPI_CALL_BASE(env, napi_get_value_int32(env, fileConflictOption,
1164             reinterpret_cast<int *>(&getDataParam->fileConflictOption)), false);
1165     }
1166     napi_value progressIndicator;
1167     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "progressIndicator", &progressIndicator), false);
1168     NAPI_CALL_BASE(env, napi_get_value_int32(env, progressIndicator,
1169         reinterpret_cast<int *>(&getDataParam->progressIndicator)), false);
1170 
1171     std::shared_ptr<ProgressListenerFn> listenerFn = std::make_shared<ProgressListenerFn>();
1172     NAPI_CALL_BASE(env, napi_get_named_property(env, in, "progressListener", &listenerFn->jsCallback), false);
1173     if (CheckParamsType(env, listenerFn->jsCallback, napi_function)) {
1174         if (!AddProgressListener(env, getDataParam, listenerFn)) {
1175             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "add listener failed!");
1176             return false;
1177         }
1178     }
1179     return true;
1180 }
1181 
GetDataWithProgressParam(std::shared_ptr<GetDataParamsContextInfo> & context)1182 void SystemPasteboardNapi::GetDataWithProgressParam(std::shared_ptr<GetDataParamsContextInfo> &context)
1183 {
1184     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
1185         // 1: GetPasteData has 0 or 1 args
1186         if (argc > 0 &&
1187             !CheckArgsType(env, argv[0], napi_object, "Parameter error. The type of object must be function.")) {
1188             return napi_invalid_arg;
1189         }
1190         if (!CheckExpression(env, ParseJsGetDataWithProgress(env, argv[0], context->getDataParams),
1191             JSErrorCode::INVALID_PARAMETERS, "Parameter error. parse param failed!")) {
1192             return napi_invalid_arg;
1193         }
1194         return napi_ok;
1195     };
1196 
1197     auto output = [context](napi_env env, napi_value *result) -> napi_status {
1198         napi_value instance = nullptr;
1199         napi_status status = PasteDataNapi::NewInstance(env, instance);
1200         if (status != napi_ok) {
1201             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "NewInstance failed!");
1202             return napi_invalid_arg;
1203         }
1204         PasteDataNapi *obj = nullptr;
1205         napi_status ret = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
1206         if ((ret == napi_ok) && (obj != nullptr)) {
1207             obj->value_ = context->pasteData;
1208         } else {
1209             return napi_generic_failure;
1210         }
1211         *result = instance;
1212         return napi_ok;
1213     };
1214     context->SetAction(std::move(input), std::move(output));
1215 }
1216 
GetDataWithProgress(napi_env env,napi_callback_info info)1217 napi_value SystemPasteboardNapi::GetDataWithProgress(napi_env env, napi_callback_info info)
1218 {
1219     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetDataWithProgress is called!");
1220     std::shared_ptr<DfxAppEvent> processorEvent = std::make_shared<DfxAppEvent>();
1221 
1222     auto context = std::make_shared<GetDataParamsContextInfo>();
1223     context->pasteData = std::make_shared<PasteData>();
1224     context->getDataParams = std::make_shared<GetDataParams>();
1225     GetDataWithProgressParam(context);
1226 
1227     auto exec = [context, processorEvent](AsyncCall::Context *ctx) {
1228         context->getDataParams->info = new (std::nothrow)ProgressInfo();
1229         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetDataWithProgress Begin");
1230         int32_t ret = PasteboardClient::GetInstance()->GetDataWithProgress(*context->pasteData,
1231             context->getDataParams);
1232         auto it = ErrorCodeMap.find(PasteboardError(ret));
1233         if (it != ErrorCodeMap.end()) {
1234             context->SetErrInfo(static_cast<int32_t>(it->second.first), it->second.second);
1235         } else {
1236             if (ret != static_cast<int32_t>(PasteboardError::E_OK)) {
1237                 context->SetErrInfo(static_cast<int32_t>(JSErrorCode::ERR_GET_DATA_FAILED),
1238                     "System error occurred during paste execution.");
1239             } else {
1240                 context->status = napi_ok;
1241             }
1242         }
1243         listenerMap_.erase("progressNotify");
1244         if (context->getDataParams->info != nullptr) {
1245             delete context->getDataParams->info;
1246             context->getDataParams->info = nullptr;
1247         }
1248         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetDataWithProgress End");
1249         PASTEBOARD_CHECK_AND_RETURN_LOGE(processorEvent != nullptr, PASTEBOARD_MODULE_JS_NAPI,
1250             "processorEvent is null");
1251         processorEvent->SetEvent("getDataWithProgress", ret, ret == static_cast<int32_t>(PasteboardError::E_OK) ?
1252             EventReportResult::EVENT_REPORT_SUCCESS : EventReportResult::EVENT_REPORT_FAIL);
1253     };
1254     // 0: the AsyncCall at the first position;
1255     AsyncCall asyncCall(env, info, context, 0);
1256     return asyncCall.Call(env, exec);
1257 }
1258 
SystemPasteboardInit(napi_env env,napi_value exports)1259 napi_value SystemPasteboardNapi::SystemPasteboardInit(napi_env env, napi_value exports)
1260 {
1261     napi_status status = napi_ok;
1262     napi_property_descriptor descriptors[] = {
1263         DECLARE_NAPI_FUNCTION("on", On),
1264         DECLARE_NAPI_FUNCTION("off", Off),
1265         DECLARE_NAPI_FUNCTION("clear", Clear),
1266         DECLARE_NAPI_FUNCTION("getPasteData", GetPasteData),
1267         DECLARE_NAPI_FUNCTION("hasPasteData", HasPasteData),
1268         DECLARE_NAPI_FUNCTION("setPasteData", SetPasteData),
1269         DECLARE_NAPI_FUNCTION("clearData", ClearData),
1270         DECLARE_NAPI_FUNCTION("getData", GetData),
1271         DECLARE_NAPI_FUNCTION("hasData", HasData),
1272         DECLARE_NAPI_FUNCTION("setData", SetData),
1273         DECLARE_NAPI_FUNCTION("isRemoteData", IsRemoteData),
1274         DECLARE_NAPI_FUNCTION("getDataSource", GetDataSource),
1275         DECLARE_NAPI_FUNCTION("getMimeTypes", GetMimeTypes),
1276         DECLARE_NAPI_FUNCTION("hasDataType", HasDataType),
1277         DECLARE_NAPI_FUNCTION("detectPatterns", DetectPatterns),
1278         DECLARE_NAPI_FUNCTION("clearDataSync", ClearDataSync),
1279         DECLARE_NAPI_FUNCTION("getDataSync", GetDataSync),
1280         DECLARE_NAPI_FUNCTION("hasDataSync", HasDataSync),
1281         DECLARE_NAPI_FUNCTION("setDataSync", SetDataSync),
1282         DECLARE_NAPI_FUNCTION("setUnifiedData", SetUnifiedData),
1283         DECLARE_NAPI_FUNCTION("getUnifiedData", GetUnifiedData),
1284         DECLARE_NAPI_FUNCTION("setUnifiedDataSync", SetUnifiedDataSync),
1285         DECLARE_NAPI_FUNCTION("getUnifiedDataSync", GetUnifiedDataSync),
1286         DECLARE_NAPI_FUNCTION("setAppShareOptions", SetAppShareOptions),
1287         DECLARE_NAPI_FUNCTION("removeAppShareOptions", RemoveAppShareOptions),
1288         DECLARE_NAPI_FUNCTION("getDataWithProgress", GetDataWithProgress),
1289         DECLARE_NAPI_FUNCTION("getChangeCount", GetChangeCount),
1290     };
1291     napi_value constructor;
1292     napi_define_class(env, "SystemPasteboard", NAPI_AUTO_LENGTH, New, nullptr,
1293         sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &constructor);
1294     if (status != napi_ok) {
1295         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to define class at SystemPasteboardInit");
1296         return nullptr;
1297     }
1298     napi_create_reference(env, constructor, 1, &g_systemPasteboard);
1299     status = napi_set_named_property(env, exports, "SystemPasteboard", constructor);
1300     if (status != napi_ok) {
1301         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Set property failed when SystemPasteboardInit");
1302         return nullptr;
1303     }
1304     return exports;
1305 }
1306 
SystemPasteboardNapi()1307 SystemPasteboardNapi::SystemPasteboardNapi() : env_(nullptr)
1308 {
1309     value_ = std::make_shared<PasteDataNapi>();
1310 }
1311 
~SystemPasteboardNapi()1312 SystemPasteboardNapi::~SystemPasteboardNapi()
1313 {
1314     value_ = nullptr;
1315 }
1316 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)1317 void SystemPasteboardNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
1318 {
1319     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Destructor");
1320     (void)nativeObject;
1321     SystemPasteboardNapi *obj = static_cast<SystemPasteboardNapi *>(nativeObject);
1322     delete obj;
1323 }
1324 
New(napi_env env,napi_callback_info info)1325 napi_value SystemPasteboardNapi::New(napi_env env, napi_callback_info info)
1326 {
1327     size_t argc = MAX_ARGS;
1328     napi_value argv[MAX_ARGS] = { 0 };
1329     napi_value thisVar = nullptr;
1330     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
1331     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "proc.");
1332     // get native object
1333     SystemPasteboardNapi *obj = new (std::nothrow) SystemPasteboardNapi();
1334     if (!obj) {
1335         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "New obj is null");
1336         return nullptr;
1337     }
1338     obj->env_ = env;
1339     ASSERT_CALL(env, napi_wrap(env, thisVar, obj, SystemPasteboardNapi::Destructor,
1340                        nullptr, // finalize_hint
1341                        nullptr), obj);
1342     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "end.");
1343     return thisVar;
1344 }
1345 
NewInstance(napi_env env,napi_value & instance)1346 napi_status SystemPasteboardNapi::NewInstance(napi_env env, napi_value &instance)
1347 {
1348     napi_status status;
1349     if (g_systemPasteboard_instance != nullptr) {
1350         status = napi_get_reference_value(env, g_systemPasteboard_instance, &instance);
1351         if (status != napi_ok) {
1352             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get instance failed");
1353             return status;
1354         }
1355         return napi_ok;
1356     }
1357 
1358     napi_value constructor;
1359     status = napi_get_reference_value(env, g_systemPasteboard, &constructor);
1360     if (status != napi_ok) {
1361         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get reference failed");
1362         return status;
1363     }
1364 
1365     status = napi_new_instance(env, constructor, 0, nullptr, &instance);
1366     if (status != napi_ok) {
1367         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "new instance failed");
1368         return status;
1369     }
1370     napi_create_reference(env, instance, 1, &g_systemPasteboard_instance);
1371     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "new instance ok");
1372 
1373     return napi_ok;
1374 }
1375 
GetObserver(napi_env env,napi_value jsCallback)1376 sptr<PasteboardObserverInstance> SystemPasteboardNapi::GetObserver(napi_env env, napi_value jsCallback)
1377 {
1378     for (const auto &[refKey, observerValue] : observers_) {
1379         napi_value callback = nullptr;
1380         napi_get_reference_value(env, refKey, &callback);
1381         bool isEqual = false;
1382         napi_strict_equals(env, jsCallback, callback, &isEqual);
1383         if (isEqual) {
1384             return observerValue;
1385         }
1386     }
1387     return nullptr;
1388 }
1389 
AddObserver(napi_env env,napi_value jsCallback)1390 void SystemPasteboardNapi::AddObserver(napi_env env, napi_value jsCallback)
1391 {
1392     PasteboardNapiScope scope(env);
1393 
1394     napi_value name = nullptr;
1395     napi_status status = napi_create_string_utf8(env, "pasteboardChanged", NAPI_AUTO_LENGTH, &name);
1396     PASTEBOARD_CHECK_AND_RETURN_LOGE(status == napi_ok, PASTEBOARD_MODULE_JS_NAPI,
1397         "create string failed, status=%{public}d", status);
1398 
1399     napi_ref ref = nullptr;
1400     status = napi_create_reference(env, jsCallback, 1, &ref);
1401     PASTEBOARD_CHECK_AND_RETURN_LOGE(status == napi_ok, PASTEBOARD_MODULE_JS_NAPI,
1402         "create reference failed, status=%{public}d", status);
1403 
1404     napi_threadsafe_function napiCallback = nullptr;
1405     status = napi_create_threadsafe_function(env, jsCallback, nullptr, name, 0, 1, nullptr, nullptr, nullptr,
1406         nullptr, &napiCallback);
1407     if (status != napi_ok) {
1408         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "create callback failed, status=%{public}d", status);
1409         napi_delete_reference(env, ref);
1410         return;
1411     }
1412 
1413     auto observer = sptr<PasteboardObserverInstance>::MakeSptr(napiCallback, env);
1414     if (observer == nullptr) {
1415         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "malloc observer failed");
1416         napi_release_threadsafe_function(napiCallback, napi_tsfn_release);
1417         napi_delete_reference(env, ref);
1418         return;
1419     }
1420 
1421     bool ret = PasteboardClient::GetInstance()->Subscribe(PasteboardObserverType::OBSERVER_LOCAL, observer);
1422     if (!ret) {
1423         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "subscribe observer failed");
1424         napi_delete_reference(env, ref);
1425         return;
1426     }
1427 
1428     observers_[ref] = observer;
1429 }
1430 
DeleteObserver(napi_env env,const sptr<PasteboardObserverInstance> & observer)1431 void SystemPasteboardNapi::DeleteObserver(napi_env env, const sptr<PasteboardObserverInstance> &observer)
1432 {
1433     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "observer == null: %{public}d, size: %{public}zu",
1434         observer == nullptr, observers_.size());
1435     std::vector<sptr<PasteboardObserverInstance>> observers;
1436     std::vector<napi_ref> refs;
1437     for (auto it = observers_.begin(); it != observers_.end();) {
1438         if (it->second == observer) {
1439             refs.push_back(it->first);
1440             observers.push_back(observer);
1441             it = observers_.erase(it);
1442             break;
1443         }
1444         if (observer == nullptr) {
1445             refs.push_back(it->first);
1446             observers.push_back(it->second);
1447             it = observers_.erase(it);
1448         } else {
1449             it++;
1450         }
1451     }
1452     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "delete observer size: %{public}zu", observers.size());
1453     for (auto &delObserver : observers) {
1454         PasteboardClient::GetInstance()->Unsubscribe(PasteboardObserverType::OBSERVER_LOCAL, delObserver);
1455     }
1456     for (auto &ref : refs) {
1457         napi_delete_reference(env, ref);
1458     }
1459 }
1460 
GetUnifiedData(const std::string & type,UDMF::UnifiedData & data)1461 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::GetUnifiedData(
1462     const std::string &type, UDMF::UnifiedData &data)
1463 {
1464     std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance(wrapper_.lock());
1465     if (delayGetterInstance == nullptr) {
1466         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "no delay getter");
1467         return;
1468     }
1469     delayGetterInstance->GetUnifiedData(type, data);
1470 }
1471 
GetPasteData(const std::string & type,MiscServices::PasteData & data)1472 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::GetPasteData(
1473     const std::string &type, MiscServices::PasteData &data)
1474 {
1475 }
1476 
SetDelayGetterWrapper(const std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance)1477 void PasteboardDelayGetterInstance::PasteboardDelayGetterImpl::SetDelayGetterWrapper(
1478     const std::shared_ptr<PasteboardDelayGetterInstance> delayGetterInstance)
1479 {
1480     wrapper_ = delayGetterInstance;
1481 }
1482 } // namespace MiscServicesNapi
1483 } // namespace OHOS