• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "cloud_sync_callback_ani.h"
17 
18 #include "ani_utils.h"
19 #include "utils_log.h"
20 
21 namespace OHOS::FileManagement::CloudSync {
22 
23 using namespace std;
24 using namespace arkts::ani_signature;
25 
26 constexpr int32_t ANI_SCOPE_SIZE = 16;
27 static const unsigned int READ_SIZE = 1024;
28 static mutex obsMutex_;
29 
30 ConcurrentMap<CloudNotifyObserver *, ObserverImpl::ObserverParam> ObserverImpl::observers_;
31 
OnChange()32 void ObserverImpl::OnChange() {}
33 
OnChangeExt(const AAFwk::ChangeInfo & info)34 void ObserverImpl::OnChangeExt(const AAFwk::ChangeInfo &info)
35 {
36     if (cloudNotifyObserver_ == nullptr) {
37         LOGE("cloudNotifyObserver_ is null!");
38         return;
39     }
40     cloudNotifyObserver_->OnChangeExt(info);
41 }
42 
GetObserver(const Uri & uri,const shared_ptr<CloudNotifyObserver> & observer)43 sptr<ObserverImpl> ObserverImpl::GetObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer)
44 {
45     lock_guard<mutex> lock(obsMutex_);
46     sptr<ObserverImpl> result = nullptr;
47     observers_.Compute(observer.get(), [&result, &uri, &observer](const auto &key, auto &value) {
48         if (value.obs_ == nullptr) {
49             value.obs_ = new (nothrow) ObserverImpl(observer);
50             value.uris_.push_back(uri);
51         } else {
52             auto it = find(value.uris_.begin(), value.uris_.end(), uri);
53             if (it == value.uris_.end()) {
54                 value.uris_.push_back(uri);
55             }
56         }
57 
58         result = value.obs_;
59         return result != nullptr;
60     });
61 
62     return result;
63 }
64 
FindObserver(const Uri & uri,const shared_ptr<CloudNotifyObserver> & observer)65 bool ObserverImpl::FindObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer)
66 {
67     lock_guard<mutex> lock(obsMutex_);
68     auto result = observers_.Find(observer.get());
69     if (result.first) {
70         auto it = std::find(result.second.uris_.begin(), result.second.uris_.end(), uri);
71         if (it == result.second.uris_.end()) {
72             return false;
73         }
74     }
75     return result.first;
76 }
77 
DeleteObserver(const Uri & uri,const shared_ptr<CloudNotifyObserver> & observer)78 bool ObserverImpl::DeleteObserver(const Uri &uri, const shared_ptr<CloudNotifyObserver> &observer)
79 {
80     lock_guard<mutex> lock(obsMutex_);
81     return observers_.ComputeIfPresent(observer.get(), [&uri](auto &key, auto &value) {
82         value.uris_.remove_if([&uri](const auto &value) { return uri == value; });
83         return !value.uris_.empty();
84     });
85 }
86 
CloudSyncCallbackAniImpl(ani_env * env,ani_ref fun)87 CloudSyncCallbackAniImpl::CloudSyncCallbackAniImpl(ani_env *env, ani_ref fun)
88 {
89     if (env == nullptr || env->GetVM(&vm_)) {
90         LOGE("CloudSyncCallbackAniImpl get vm failed.");
91         return;
92     }
93     if (fun != nullptr) {
94         cbOnRef_ = fun;
95     }
96 }
97 
GetSyncProgress(CloudSyncState state,ErrorType error,const ani_class & cls,ani_object & pg)98 void CloudSyncCallbackAniImpl::GetSyncProgress(
99     CloudSyncState state, ErrorType error, const ani_class &cls, ani_object &pg)
100 {
101     ani_env *env = nullptr;
102     if (vm_ == nullptr || vm_->GetEnv(ANI_VERSION_1, &env)) {
103         LOGE("CloudSyncCallbackAniImpl get env failed.");
104         return;
105     }
106     ani_method ctor;
107     std::string ct = Builder::BuildConstructorName();
108     std::string argSign = Builder::BuildSignatureDescriptor({
109         Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.SyncState"),
110         Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.ErrorType")
111     });
112     ani_status ret = env->Class_FindMethod(cls, ct.c_str(), argSign.c_str(), &ctor);
113     if (ret != ANI_OK) {
114         LOGE("find ctor method failed. ret = %{public}d", ret);
115         return;
116     }
117 
118     ani_enum stateEnum;
119     Type stateSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.SyncState");
120     env->FindEnum(stateSign.Descriptor().c_str(), &stateEnum);
121     ani_enum errorEnum;
122     Type errorSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.ErrorType");
123     env->FindEnum(errorSign.Descriptor().c_str(), &errorEnum);
124 
125     ani_enum_item stateEnumItem;
126     env->Enum_GetEnumItemByIndex(stateEnum, state, &stateEnumItem);
127     ani_enum_item errorEnumItem;
128     env->Enum_GetEnumItemByIndex(errorEnum, error, &errorEnumItem);
129 
130     ret = env->Object_New(cls, ctor, &pg, stateEnumItem, errorEnumItem);
131     if (ret != ANI_OK) {
132         LOGE("create new object failed. ret = %{public}d", ret);
133     }
134 }
135 
OnSyncStateChanged(CloudSyncState state,ErrorType error)136 void CloudSyncCallbackAniImpl::OnSyncStateChanged(CloudSyncState state, ErrorType error)
137 {
138     auto task = [this, state, error]() {
139         LOGI("OnSyncStateChanged state is %{public}d, error is %{public}d", state, error);
140         ani_env *tmpEnv = nullptr;
141         if (vm_ == nullptr || vm_->GetEnv(ANI_VERSION_1, &tmpEnv)) {
142             LOGE("CloudSyncCallbackAniImpl get env failed.");
143             return;
144         }
145         ani_size nr_refs = ANI_SCOPE_SIZE;
146         ani_status ret = tmpEnv->CreateLocalScope(nr_refs);
147         if (ret != ANI_OK) {
148             LOGE("crete local scope failed. ret = %{public}d", ret);
149             return;
150         }
151         ani_namespace ns {};
152         Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync");
153         ret = tmpEnv->FindNamespace(nsSign.Descriptor().c_str(), &ns);
154         if (ret != ANI_OK) {
155             LOGE("find namespace failed. ret = %{public}d", ret);
156             return;
157         }
158         Type clsName = Builder::BuildClass("SyncProgressInner");
159         ani_class cls;
160         ret = tmpEnv->Namespace_FindClass(ns, clsName.Descriptor().c_str(), &cls);
161         if (ret != ANI_OK) {
162             LOGE("find class failed. ret = %{public}d", ret);
163             return;
164         }
165         ani_object pg;
166         GetSyncProgress(state, error, cls, pg);
167         ani_ref ref_;
168         ani_fn_object etsCb = reinterpret_cast<ani_fn_object>(cbOnRef_);
169         std::vector<ani_ref> vec = { pg };
170         ret = tmpEnv->FunctionalObject_Call(etsCb, 1, vec.data(), &ref_);
171         if (ret != ANI_OK) {
172             LOGE("ani call function failed. ret = %{public}d", ret);
173             return;
174         }
175         ret = tmpEnv->DestroyLocalScope();
176         if (ret != ANI_OK) {
177             LOGE("failed to DestroyLocalScope. ret = %{public}d", ret);
178         }
179     };
180     if (!ANIUtils::SendEventToMainThread(task)) {
181         LOGE("failed to send event");
182     }
183 }
184 
DeleteReference()185 void CloudSyncCallbackAniImpl::DeleteReference()
186 {
187     ani_env *env = nullptr;
188     if (vm_ == nullptr || vm_->GetEnv(ANI_VERSION_1, &env)) {
189         LOGE("CloudSyncCallbackAniImpl get env failed.");
190         return;
191     }
192     if (cbOnRef_ != nullptr) {
193         env->GlobalReference_Delete(cbOnRef_);
194         cbOnRef_ = nullptr;
195     }
196 }
197 
OnSyncStateChanged(SyncType type,SyncPromptState state)198 void CloudSyncCallbackAniImpl::OnSyncStateChanged(SyncType type, SyncPromptState state)
199 {
200     return;
201 }
202 
SetValueArray(ani_env * env,const std::list<Uri> listValue,ani_object & uris)203 ani_status ChangeListenerAni::SetValueArray(ani_env *env, const std::list<Uri> listValue, ani_object &uris)
204 {
205     ani_class arrayCls = nullptr;
206     Type arrSign = Builder::BuildClass("escompat.Array");
207     ani_status ret = env->FindClass(arrSign.Descriptor().c_str(), &arrayCls);
208     if (ret != ANI_OK) {
209         LOGE("find ani array failed. ret = %{public}d", static_cast<int32_t>(ret));
210         return ret;
211     }
212 
213     ani_method arrayCtor;
214     std::string ct = Builder::BuildConstructorName();
215     std::string ctSign = Builder::BuildSignatureDescriptor({Builder::BuildInt()});
216     ret = env->Class_FindMethod(arrayCls, ct.c_str(), ctSign.c_str(), &arrayCtor);
217     if (ret != ANI_OK) {
218         LOGE("array find method failed. ret = %{public}d", static_cast<int32_t>(ret));
219         return ret;
220     }
221 
222     std::vector<std::string> strings(listValue.size());
223     int elementIndex = 0;
224     for (auto uri : listValue) {
225         strings[elementIndex++] = uri.ToString();
226     }
227 
228     ret = env->Object_New(arrayCls, arrayCtor, &uris, strings.size());
229     if (ret != ANI_OK) {
230         LOGE("set array uri new object failed. ret = %{public}d", static_cast<int32_t>(ret));
231         return ret;
232     }
233 
234     ani_size index = 0;
235     for (auto str : strings) {
236         ani_string ani_str;
237         ret = env->String_NewUTF8(str.c_str(), str.size(), &ani_str);
238         if (ret != ANI_OK) {
239             LOGE("std string to ani string failed. ret = %{public}d", static_cast<int32_t>(ret));
240             return ret;
241         }
242         std::string setSign = Builder::BuildSignatureDescriptor({Builder::BuildInt(), Builder::BuildNull()});
243         ret = env->Object_CallMethodByName_Void(uris, "$_set", setSign.c_str(), index, ani_str);
244         if (ret != ANI_OK) {
245             LOGE("set array uri value failed. ret = %{public}d", static_cast<int32_t>(ret));
246             return ret;
247         }
248         index++;
249     }
250     return ANI_OK;
251 }
252 
SetIsDir(ani_env * env,const shared_ptr<MessageParcel> parcel,ani_object & isDirectory)253 ani_status ChangeListenerAni::SetIsDir(ani_env *env, const shared_ptr<MessageParcel> parcel, ani_object &isDirectory)
254 {
255     uint32_t len = 0;
256     if (!parcel->ReadUint32(len)) {
257         LOGE("Failed to read sub uri list length");
258         return ANI_INVALID_ARGS;
259     }
260     if (len > READ_SIZE) {
261         return ANI_INVALID_ARGS;
262     }
263     ani_class arrayCls = nullptr;
264     Type arrSign = Builder::BuildClass("escompat.Array");
265     ani_status ret = env->FindClass(arrSign.Descriptor().c_str(), &arrayCls);
266     if (ret != ANI_OK) {
267         LOGE("find ani array failed. ret = %{public}d", static_cast<int32_t>(ret));
268         return ret;
269     }
270 
271     ani_method arrayCtor;
272     std::string ct = Builder::BuildConstructorName();
273     std::string ctSign = Builder::BuildSignatureDescriptor({Builder::BuildInt()});
274     ret = env->Class_FindMethod(arrayCls, ct.c_str(), ctSign.c_str(), &arrayCtor);
275     if (ret != ANI_OK) {
276         LOGE("array find method failed. ret = %{public}d", static_cast<int32_t>(ret));
277         return ret;
278     }
279     std::vector<bool> isDirs(len);
280     for (uint32_t i = 0; i < len; i++) {
281         isDirs[i] = parcel->ReadBool();
282     }
283     ret = env->Object_New(arrayCls, arrayCtor, &isDirectory, isDirs.size());
284     if (ret != ANI_OK) {
285         LOGE("set array uri new object failed. ret = %{public}d", static_cast<int32_t>(ret));
286         return ret;
287     }
288     ani_size index = 0;
289     for (auto isDir : isDirs) {
290         std::string setSign = Builder::BuildSignatureDescriptor({Builder::BuildInt(), Builder::BuildNull()});
291         ret = env->Object_CallMethodByName_Void(
292             isDirectory, "$_set", setSign.c_str(), index, static_cast<ani_boolean>(isDir));
293         if (ret != ANI_OK) {
294             LOGE("set array uri value failed. ret = %{public}d", static_cast<int32_t>(ret));
295             return ret;
296         }
297         index++;
298     }
299     return ANI_OK;
300 }
301 
GetChangeDataObject(ani_env * env,CloudChangeListener & listener,ani_class cls,ani_object & changeData)302 ani_status ChangeListenerAni::GetChangeDataObject(
303     ani_env *env, CloudChangeListener &listener, ani_class cls, ani_object &changeData)
304 {
305     ani_object uris;
306     ani_status ret = SetValueArray(env, listener.changeInfo.uris_, uris);
307     if (ret != ANI_OK) {
308         LOGE("set array uris failed. ret = %{public}d", ret);
309         return ret;
310     }
311     ani_object isDirectory;
312     if (listener.changeInfo.size_ > 0) {
313         shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
314         if (parcel->ParseFrom(reinterpret_cast<uintptr_t>(listener.changeInfo.data_), listener.changeInfo.size_)) {
315             ret = SetIsDir(env, parcel, isDirectory);
316             if (ret != ANI_OK) {
317                 LOGE("Set subArray named property error! field: subUris");
318                 return ret;
319             }
320         }
321     }
322     ani_enum notifyTypeEnum;
323     Type notifyTypeSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.NotifyType");
324     env->FindEnum(notifyTypeSign.Descriptor().c_str(), &notifyTypeEnum);
325     ani_enum_item notifyTypeEnumItem;
326     env->Enum_GetEnumItemByIndex(notifyTypeEnum, listener.changeInfo.changeType_, &notifyTypeEnumItem);
327     ani_method ctor;
328     std::string ct = Builder::BuildConstructorName();
329     std::string ctSign = Builder::BuildSignatureDescriptor({notifyTypeSign,
330         Builder::BuildClass("escompat.Array"), Builder::BuildClass("escompat.Array")});
331     ret = env->Class_FindMethod(cls, ct.c_str(), ctSign.c_str(), &ctor);
332     if (ret != ANI_OK) {
333         LOGE("find ctor method failed. ret = %{public}d", ret);
334         return ret;
335     }
336     ret = env->Object_New(cls, ctor, &changeData, notifyTypeEnumItem, isDirectory, uris);
337     if (ret != ANI_OK) {
338         LOGE("create new object failed. ret = %{public}d", ret);
339         return ret;
340     }
341     return ANI_OK;
342 }
343 
OnChange(CloudChangeListener & listener,const ani_ref cbRef)344 void ChangeListenerAni::OnChange(CloudChangeListener &listener, const ani_ref cbRef)
345 {
346     auto task = [this, listener, cbRef]() {
347         LOGI("ChangeListenerAni OnChange");
348         ani_env *tmpEnv = env_;
349         ani_size nr_refs = ANI_SCOPE_SIZE;
350         ani_status ret = tmpEnv->CreateLocalScope(nr_refs);
351         if (ret != ANI_OK) {
352             LOGE("crete local scope failed. ret = %{public}d", ret);
353             return;
354         }
355         CloudChangeListener tmpListener = listener;
356         if (tmpListener.changeInfo.uris_.empty()) {
357             return;
358         }
359         ani_namespace ns {};
360         Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync");
361         ret = tmpEnv->FindNamespace(nsSign.Descriptor().c_str(), &ns);
362         if (ret != ANI_OK) {
363             LOGE("find namespace failed. ret = %{public}d", ret);
364             return;
365         }
366         Type clsName = Builder::BuildClass("ChangeDataInner");
367         ani_class cls;
368         ret = tmpEnv->Namespace_FindClass(ns, clsName.Descriptor().c_str(), &cls);
369         if (ret != ANI_OK) {
370             LOGE("find class failed. ret = %{public}d", ret);
371             return;
372         }
373         ani_object changeData;
374         ret = GetChangeDataObject(tmpEnv, tmpListener, cls, changeData);
375         ani_ref ref_;
376         ani_fn_object etsCb = reinterpret_cast<ani_fn_object>(cbRef);
377         std::vector<ani_ref> vec = { changeData };
378         ret = tmpEnv->FunctionalObject_Call(etsCb, 1, vec.data(), &ref_);
379         if (ret != ANI_OK) {
380             LOGE("ani call function failed. ret = %{public}d", ret);
381             return;
382         }
383         ret = tmpEnv->DestroyLocalScope();
384         if (ret != ANI_OK) {
385             LOGE("failed to DestroyLocalScope. ret = %{public}d", ret);
386         }
387     };
388     if (!ANIUtils::SendEventToMainThread(task)) {
389         LOGE("failed to send event");
390     }
391 }
392 
OnChange()393 void CloudNotifyObserver::OnChange() {}
394 
OnChangeExt(const AAFwk::ChangeInfo & changeInfo)395 void CloudNotifyObserver::OnChangeExt(const AAFwk::ChangeInfo &changeInfo)
396 {
397     CloudChangeListener listener;
398     listener.changeInfo = changeInfo;
399     listener.strUri = uri_;
400     listObj_.OnChange(listener, ref_);
401 }
402 
GetOptimProgress(ani_env * env,OptimizeState state,int32_t progress,ani_class cls,ani_object & data)403 ani_status CloudOptimizeCallbackAniImpl::GetOptimProgress(
404     ani_env *env, OptimizeState state, int32_t progress, ani_class cls, ani_object &data)
405 {
406     LOGI("CloudOptimizeCallbackAniImpl OnOptimizeProcess");
407     ani_enum optimizeStateEnum;
408     Type optimizeStateSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.OptimizeState");
409     ani_status ret = env->FindEnum(optimizeStateSign.Descriptor().c_str(), &optimizeStateEnum);
410     if (ret != ANI_OK) {
411         LOGE("find optim state failed. ret = %{public}d", ret);
412         return ret;
413     }
414     ani_enum_item optimizeStateTypeEnumItem;
415     ret = env->Enum_GetEnumItemByIndex(optimizeStateEnum, state, &optimizeStateTypeEnumItem);
416     if (ret != ANI_OK) {
417         LOGE("set optim state item failed. ret = %{public}d", ret);
418         return ret;
419     }
420 
421     ani_method ctor;
422     std::string ct = Builder::BuildConstructorName();
423     std::string ctSign = Builder::BuildSignatureDescriptor({optimizeStateSign, Builder::BuildDouble()});
424     ret = env->Class_FindMethod(cls, ct.c_str(), ctSign.c_str(), &ctor);
425     if (ret != ANI_OK) {
426         LOGE("find ctor method failed. ret = %{public}d", ret);
427         return ret;
428     }
429 
430     ret = env->Object_New(cls, ctor, &data, optimizeStateTypeEnumItem, static_cast<double>(progress));
431     if (ret != ANI_OK) {
432         LOGE("create new object failed. ret = %{public}d", ret);
433         return ret;
434     }
435     return ANI_OK;
436 }
437 
OnOptimizeProcess(const OptimizeState state,const int32_t progress)438 void CloudOptimizeCallbackAniImpl::OnOptimizeProcess(const OptimizeState state, const int32_t progress)
439 {
440     auto task = [this, state, progress]() {
441         if (!cbOnRef_) {
442             LOGE("cbOnRef_ is nullptr");
443             return;
444         }
445         ani_env *tmpEnv = env_;
446         ani_size nr_refs = ANI_SCOPE_SIZE;
447         ani_status ret = tmpEnv->CreateLocalScope(nr_refs);
448         if (ret != ANI_OK) {
449             LOGE("crete local scope failed. ret = %{public}d", ret);
450             return;
451         }
452         ani_namespace ns {};
453         Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync");
454         ret = tmpEnv->FindNamespace(nsSign.Descriptor().c_str(), &ns);
455         if (ret != ANI_OK) {
456             LOGE("find namespace failed. ret = %{public}d", ret);
457             return;
458         }
459         Type clsName = Builder::BuildClass("OptimizeSpaceProgressInner");
460         ani_class cls;
461         ret = tmpEnv->Namespace_FindClass(ns, clsName.Descriptor().c_str(), &cls);
462         if (ret != ANI_OK) {
463             LOGE("find class failed. ret = %{public}d", ret);
464             return;
465         }
466         ani_object optimProgressData;
467         ret = GetOptimProgress(tmpEnv, state, progress, cls, optimProgressData);
468         if (ret != ANI_OK) {
469             LOGE("GetOptimProgress failed. ret = %{public}d", ret);
470             return;
471         }
472         ani_ref ref_;
473         ani_fn_object etsCb = reinterpret_cast<ani_fn_object>(cbOnRef_);
474         std::vector<ani_ref> vec = { optimProgressData };
475         ret = tmpEnv->FunctionalObject_Call(etsCb, 1, vec.data(), &ref_);
476         if (ret != ANI_OK) {
477             LOGE("ani call function failed. ret = %{public}d", ret);
478             return;
479         }
480         ret = tmpEnv->DestroyLocalScope();
481         if (ret != ANI_OK) {
482             LOGE("failed to DestroyLocalScope. ret = %{public}d", ret);
483         }
484     };
485     if (!ANIUtils::SendEventToMainThread(task)) {
486         LOGE("failed to send event");
487     }
488 }
489 } // namespace OHOS::FileManagement::CloudSync