• 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_ani.h"
17 
18 #include "ani_utils.h"
19 #include "cloud_sync_callback_ani.h"
20 #include "dfs_error.h"
21 #include "dfsu_access_token_helper.h"
22 #include "error_handler.h"
23 #include "utils_log.h"
24 
25 namespace OHOS::FileManagement::CloudSync {
26 
27 using namespace arkts::ani_signature;
28 
29 const string FILE_SCHEME = "file";
30 const int32_t E_IPCSS = 13600001;
31 const int32_t E_PERMISSION = 201;
32 thread_local unique_ptr<ChangeListenerAni> g_listObj = nullptr;
33 mutex CloudSyncAni::sOnOffMutex_;
34 
CloudSyncUnwrap(ani_env * env,ani_object object)35 static CloudSyncCore *CloudSyncUnwrap(ani_env *env, ani_object object)
36 {
37     ani_long nativePtr;
38     auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr);
39     if (ret != ANI_OK) {
40         LOGE("Unwrap cloudsyncCore err: %{public}d", static_cast<int32_t>(ret));
41         return nullptr;
42     }
43     std::uintptr_t ptrValue = static_cast<std::uintptr_t>(nativePtr);
44     CloudSyncCore *cloudSync = reinterpret_cast<CloudSyncCore *>(ptrValue);
45     return cloudSync;
46 }
47 
CloudSyncConstructor(ani_env * env,ani_object object)48 void CloudSyncAni::CloudSyncConstructor(ani_env *env, ani_object object)
49 {
50     ani_namespace ns {};
51     Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync");
52     ani_status ret = env->FindNamespace(nsSign.Descriptor().c_str(), &ns);
53     if (ret != ANI_OK) {
54         LOGE("find namespace failed. ret = %{public}d", static_cast<int32_t>(ret));
55         ErrorHandler::Throw(env, ENOMEM);
56         return;
57     }
58     Type clsName = Builder::BuildClass("GallerySync");
59     ani_class cls;
60     ret = env->Namespace_FindClass(ns, clsName.Descriptor().c_str(), &cls);
61     if (ret != ANI_OK) {
62         LOGE("find class failed. ret = %{public}d", static_cast<int32_t>(ret));
63         ErrorHandler::Throw(env, ENOMEM);
64         return;
65     }
66 
67     ani_method bindNativePtr;
68     std::string bindSign = Builder::BuildSignatureDescriptor({Builder::BuildLong()});
69     ret = env->Class_FindMethod(cls, "bindNativePtr", bindSign.c_str(), &bindNativePtr);
70     if (ret != ANI_OK) {
71         LOGE("find class ctor. ret = %{public}d", static_cast<int32_t>(ret));
72         ErrorHandler::Throw(env, ENOMEM);
73         return;
74     }
75 
76     FsResult<CloudSyncCore *> data = CloudSyncCore::Constructor();
77     if (!data.IsSuccess()) {
78         LOGE("cloudsync constructor failed.");
79         const auto &err = data.GetError();
80         ErrorHandler::Throw(env, err);
81         return;
82     }
83 
84     const CloudSyncCore *cloudSync = data.GetData().value();
85     ret = env->Object_CallMethod_Void(object, bindNativePtr, reinterpret_cast<ani_long>(cloudSync));
86     if (ret != ANI_OK) {
87         LOGE("bindNativePtr failed.");
88         delete cloudSync;
89         ErrorHandler::Throw(env, ENOMEM);
90     }
91 }
92 
CloudSyncOn(ani_env * env,ani_object object,ani_string evt,ani_object fun)93 void CloudSyncAni::CloudSyncOn(ani_env *env, ani_object object, ani_string evt, ani_object fun)
94 {
95     ani_ref cbOnRef;
96     ani_status ret = env->GlobalReference_Create(reinterpret_cast<ani_ref>(fun), &cbOnRef);
97     if (ret != ANI_OK) {
98         LOGE("cloud sync on create global reference failed. ret = %{public}d", ret);
99         ErrorHandler::Throw(env, E_IPCSS);
100         return;
101     }
102     auto callback = std::make_shared<CloudSyncCallbackAniImpl>(env, cbOnRef);
103 
104     std::string event;
105     ret = ANIUtils::AniString2String(env, evt, event);
106     if (ret != ANI_OK) {
107         ErrorHandler::Throw(env, E_IPCSS);
108         return;
109     }
110 
111     auto cloudSync = CloudSyncUnwrap(env, object);
112     if (cloudSync == nullptr) {
113         LOGE("Cannot wrap cloudsync.");
114         ErrorHandler::Throw(env, E_IPCSS);
115         return;
116     }
117     auto data = cloudSync->DoOn(event, callback);
118     if (!data.IsSuccess()) {
119         const auto &err = data.GetError();
120         LOGE("cloud sync do on failed, ret = %{public}d", err.GetErrNo());
121         ErrorHandler::Throw(env, err);
122     }
123 }
124 
CloudSyncOff0(ani_env * env,ani_object object,ani_string evt,ani_object fun)125 void CloudSyncAni::CloudSyncOff0(ani_env *env, ani_object object, ani_string evt, ani_object fun)
126 {
127     ani_ref cbOnRef;
128     ani_status ret = env->GlobalReference_Create(reinterpret_cast<ani_ref>(fun), &cbOnRef);
129     if (ret != ANI_OK) {
130         LOGE("cloud sync off create global reference failed. ret = %{public}d", ret);
131         ErrorHandler::Throw(env, E_IPCSS);
132         return;
133     }
134     auto callback = std::make_shared<CloudSyncCallbackAniImpl>(env, cbOnRef);
135 
136     std::string event;
137     ret = ANIUtils::AniString2String(env, evt, event);
138     if (ret != ANI_OK) {
139         ErrorHandler::Throw(env, E_IPCSS);
140         return;
141     }
142 
143     auto cloudSync = CloudSyncUnwrap(env, object);
144     if (cloudSync == nullptr) {
145         LOGE("Cannot wrap cloudsync.");
146         ErrorHandler::Throw(env, E_IPCSS);
147         return;
148     }
149     auto data = cloudSync->DoOff(event, callback);
150     if (!data.IsSuccess()) {
151         const auto &err = data.GetError();
152         LOGE("cloud sync do off failed, ret = %{public}d", err.GetErrNo());
153         ErrorHandler::Throw(env, err);
154     }
155 }
156 
CloudSyncOff1(ani_env * env,ani_object object,ani_string evt)157 void CloudSyncAni::CloudSyncOff1(ani_env *env, ani_object object, ani_string evt)
158 {
159     std::string event;
160     ani_status ret = ANIUtils::AniString2String(env, evt, event);
161     if (ret != ANI_OK) {
162         LOGE("cloud sync off create global reference failed. ret = %{public}d", ret);
163         ErrorHandler::Throw(env, E_IPCSS);
164         return;
165     }
166 
167     auto cloudSync = CloudSyncUnwrap(env, object);
168     if (cloudSync == nullptr) {
169         LOGE("Cannot wrap cloudsync.");
170         ErrorHandler::Throw(env, E_IPCSS);
171         return;
172     }
173     auto data = cloudSync->DoOff(event);
174     if (!data.IsSuccess()) {
175         const auto &err = data.GetError();
176         LOGE("cloud sync do off failed, ret = %{public}d", err.GetErrNo());
177         ErrorHandler::Throw(env, err);
178     }
179 }
180 
CloudSyncStart(ani_env * env,ani_object object)181 void CloudSyncAni::CloudSyncStart(ani_env *env, ani_object object)
182 {
183     auto cloudSync = CloudSyncUnwrap(env, object);
184     if (cloudSync == nullptr) {
185         LOGE("Cannot wrap cloudsync.");
186         ErrorHandler::Throw(env, E_PERMISSION);
187         return;
188     }
189     auto data = cloudSync->DoStart();
190     if (!data.IsSuccess()) {
191         const auto &err = data.GetError();
192         LOGE("cloud sync do start failed, ret = %{public}d", err.GetErrNo());
193         ErrorHandler::Throw(env, err);
194     }
195 }
196 
CloudSyncStop(ani_env * env,ani_object object)197 void CloudSyncAni::CloudSyncStop(ani_env *env, ani_object object)
198 {
199     auto cloudSync = CloudSyncUnwrap(env, object);
200     if (cloudSync == nullptr) {
201         LOGE("Cannot wrap cloudsync.");
202         ErrorHandler::Throw(env, E_PERMISSION);
203         return;
204     }
205     auto data = cloudSync->DoStop();
206     if (!data.IsSuccess()) {
207         const auto &err = data.GetError();
208         LOGE("cloud sync do stop failed, ret = %{public}d", err.GetErrNo());
209         ErrorHandler::Throw(env, err);
210     }
211 }
212 
OptimizeStorage(ani_env * env,ani_class clazz)213 void CloudSyncAni::OptimizeStorage(ani_env *env, ani_class clazz)
214 {
215     auto data = CloudSyncCore::DoOptimizeStorage();
216     if (!data.IsSuccess()) {
217         const auto &err = data.GetError();
218         LOGE("cloud sync do OptimizeStorage failed, ret = %{public}d", err.GetErrNo());
219         ErrorHandler::Throw(env, err);
220     }
221 }
222 
StartOptimizeStorage(ani_env * env,ani_class clazz,ani_object optim,ani_object fun)223 void CloudSyncAni::StartOptimizeStorage(ani_env *env, ani_class clazz, ani_object optim, ani_object fun)
224 {
225     OptimizeSpaceOptions optimizeOptions {};
226     ani_double totalSize;
227     ani_status ret = env->Object_GetPropertyByName_Double(optim, "totalSize", &totalSize);
228     if (ret != ANI_OK) {
229         LOGE("get totalSize failed. ret = %{public}d", ret);
230         ErrorHandler::Throw(env, E_IPCSS);
231         return;
232     }
233     ani_double agingDays;
234     ret = env->Object_GetPropertyByName_Double(optim, "agingDays", &agingDays);
235     if (ret != ANI_OK) {
236         LOGE("get agingDays failed. ret = %{public}d", ret);
237         ErrorHandler::Throw(env, E_IPCSS);
238         return;
239     }
240 
241     LOGI("totalSize: %{public}lld, agingDays:%{public}d",
242         static_cast<long long>(totalSize), static_cast<int32_t>(agingDays));
243     optimizeOptions.totalSize = static_cast<int64_t>(totalSize);
244     optimizeOptions.agingDays = static_cast<int32_t>(agingDays);
245 
246     ani_ref cbOnRef;
247     ret = env->GlobalReference_Create(reinterpret_cast<ani_ref>(fun), &cbOnRef);
248     if (ret != ANI_OK) {
249         LOGE("start optim storage create reference failed. ret = %{public}d", ret);
250         ErrorHandler::Throw(env, E_IPCSS);
251         return;
252     }
253     auto callback = std::make_shared<CloudOptimizeCallbackAniImpl>(env, cbOnRef);
254 
255     auto data = CloudSyncCore::DoStartOptimizeStorage(optimizeOptions, callback);
256     if (!data.IsSuccess()) {
257         const auto &err = data.GetError();
258         LOGE("cloud sync do StopOptimizeStorage failed, ret = %{public}d", err.GetErrNo());
259         ErrorHandler::Throw(env, err);
260     }
261 }
262 
StopOptimizeStorage(ani_env * env,ani_class clazz)263 void CloudSyncAni::StopOptimizeStorage(ani_env *env, ani_class clazz)
264 {
265     auto data = CloudSyncCore::DoStopOptimizeStorage();
266     if (!data.IsSuccess()) {
267         const auto &err = data.GetError();
268         LOGE("cloud sync do StopOptimizeStorage failed, ret = %{public}d", err.GetErrNo());
269         ErrorHandler::Throw(env, err);
270     }
271 }
272 
GetFileSyncState(ani_env * env,ani_class clazz,ani_string path)273 ani_int CloudSyncAni::GetFileSyncState(ani_env *env, ani_class clazz, ani_string path)
274 {
275     string filePath;
276     ani_status ret = ANIUtils::AniString2String(env, path, filePath);
277     if (ret != ANI_OK) {
278         LOGE("ani string get size failed. ret = %{public}d", static_cast<int32_t>(ret));
279         ErrorHandler::Throw(env, E_IPCSS);
280         return static_cast<int32_t>(ret);
281     }
282     auto data = CloudSyncCore::DoGetFileSyncState(filePath);
283     if (!data.IsSuccess()) {
284         const auto &err = data.GetError();
285         LOGE("cloud sync do GetFileSyncState failed, ret = %{public}d", err.GetErrNo());
286         ErrorHandler::Throw(env, err);
287         return err.GetErrNo();
288     }
289     return static_cast<ani_int>(data.GetData().value());
290 }
291 
CheckIsValidUri(Uri uri)292 static bool CheckIsValidUri(Uri uri)
293 {
294     string scheme = uri.GetScheme();
295     if (scheme != FILE_SCHEME) {
296         return false;
297     }
298     string sandboxPath = uri.GetPath();
299     char realPath[PATH_MAX + 1] { '\0' };
300     if (sandboxPath.length() > PATH_MAX) {
301         LOGE("sandboxPath length is too long.");
302         return false;
303     }
304     if (realpath(sandboxPath.c_str(), realPath) == nullptr) {
305         LOGE("realpath failed with %{public}d", errno);
306         return false;
307     }
308     if (strncmp(realPath, sandboxPath.c_str(), sandboxPath.size()) != 0) {
309         LOGE("sandboxPath is not equal to realPath");
310         return false;
311     }
312     if (sandboxPath.find("/data/storage/el2/cloud") != 0) {
313         LOGE("not surported uri");
314         return false;
315     }
316     return true;
317 }
318 
RegisterToObs(const RegisterParams & registerParams)319 int32_t CloudSyncAni::RegisterToObs(const RegisterParams &registerParams)
320 {
321     auto observer = make_shared<CloudNotifyObserver>(*g_listObj, registerParams.uri, registerParams.cbOnRef);
322     Uri uri(registerParams.uri);
323     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
324     if (obsMgrClient == nullptr) {
325         LOGE("get DataObsMgrClient failed");
326         return E_SA_LOAD_FAILED;
327     }
328     sptr<ObserverImpl> obs = ObserverImpl::GetObserver(uri, observer);
329     if (obs == nullptr) {
330         LOGE("new ObserverImpl failed");
331         return E_INVAL_ARG;
332     }
333     ErrCode ret = obsMgrClient->RegisterObserverExt(uri, obs, registerParams.recursion);
334     if (ret != E_OK) {
335         LOGE("ObsMgr register fail");
336         ObserverImpl::DeleteObserver(uri, observer);
337         return E_INVAL_ARG;
338     }
339     lock_guard<mutex> lock(CloudSyncAni::sOnOffMutex_);
340     g_listObj->observers_.push_back(observer);
341     return E_OK;
342 }
343 
CheckRef(ani_env * env,ani_ref ref,ChangeListenerAni & listObj,const string & uri)344 bool CloudSyncAni::CheckRef(ani_env *env, ani_ref ref, ChangeListenerAni &listObj, const string &uri)
345 {
346     ani_boolean isSame = false;
347     shared_ptr<CloudNotifyObserver> obs;
348     string obsUri;
349     {
350         std::lock_guard<mutex> lock(CloudSyncAni::sOnOffMutex_);
351         for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
352             ani_status ret = env->Reference_StrictEquals(ref, (*it)->ref_, &isSame);
353             if (ret != ANI_OK) {
354                 LOGE("compare ref failed. ret = %{public}d", static_cast<int32_t>(ret));
355                 return false;
356             }
357 
358             if (isSame) {
359                 obsUri = (*it)->uri_;
360                 if (uri.compare(obsUri) != 0) {
361                     return true;
362                 }
363                 return false;
364             }
365         }
366     }
367     return true;
368 }
369 
GetRegisterParams(ani_env * env,ani_string uri,ani_boolean recursion,ani_object fun,RegisterParams & registerParams)370 int32_t CloudSyncAni::GetRegisterParams(
371     ani_env *env, ani_string uri, ani_boolean recursion, ani_object fun, RegisterParams &registerParams)
372 {
373     std::string uriInput;
374     ani_status ret = ANIUtils::AniString2String(env, uri, uriInput);
375     if (ret != ANI_OK) {
376         LOGE("get register param get uri failed. ret = %{public}d", static_cast<int32_t>(ret));
377         return static_cast<int32_t>(ret);
378     }
379     registerParams.uri = uriInput;
380     if (!CheckIsValidUri(Uri(registerParams.uri))) {
381         LOGE("RegisterChange uri parameter format error!");
382         return E_PARAMS;
383     }
384     registerParams.recursion = recursion;
385     ret = env->GlobalReference_Create(reinterpret_cast<ani_ref>(fun), &registerParams.cbOnRef);
386     if (ret != ANI_OK) {
387         LOGE("get register param create ref failed. ret = %{public}d", static_cast<int32_t>(ret));
388         return static_cast<int32_t>(ret);
389     }
390 
391     return E_OK;
392 }
393 
RegisterChange(ani_env * env,ani_class clazz,ani_string uri,ani_boolean recursion,ani_object fun)394 void CloudSyncAni::RegisterChange(ani_env *env, ani_class clazz, ani_string uri, ani_boolean recursion, ani_object fun)
395 {
396     if (g_listObj == nullptr) {
397         g_listObj = make_unique<ChangeListenerAni>(env);
398     }
399 
400     RegisterParams registerParams;
401     int32_t ret = GetRegisterParams(env, uri, recursion, fun, registerParams);
402     if (ret != ERR_OK) {
403         LOGE("Get Params fail");
404         ErrorHandler::Throw(env, E_PARAMS);
405         return;
406     }
407 
408     if (CheckRef(env, registerParams.cbOnRef, *g_listObj, registerParams.uri)) {
409         ret = RegisterToObs(registerParams);
410         if (ret != E_OK) {
411             LOGE("Get Params fail");
412             ErrorHandler::Throw(env, E_PARAMS);
413             return;
414         }
415     } else {
416         LOGE("Check Ref fail");
417         ErrorHandler::Throw(env, E_PARAMS);
418         env->GlobalReference_Delete(registerParams.cbOnRef);
419         return;
420     }
421 }
422 
UnregisterFromObs(ani_env * env,std::string uri)423 void CloudSyncAni::UnregisterFromObs(ani_env *env, std::string uri)
424 {
425     if (!CheckIsValidUri(Uri(uri))) {
426         LOGE("unavaiable uri.");
427         ErrorHandler::Throw(env, E_PARAMS);
428         return;
429     }
430 
431     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
432     if (obsMgrClient == nullptr) {
433         LOGE("get DataObsMgrClient failed");
434         ErrorHandler::Throw(env, E_IPCSS);
435         return;
436     }
437     std::vector<std::shared_ptr<CloudNotifyObserver>> offObservers;
438     {
439         std::lock_guard<mutex> lock(CloudSyncAni::sOnOffMutex_);
440         for (auto iter = g_listObj->observers_.begin(); iter != g_listObj->observers_.end();) {
441             if (uri == (*iter)->uri_) {
442                 offObservers.push_back(*iter);
443                 vector<shared_ptr<CloudNotifyObserver>>::iterator tmp = iter;
444                 iter = g_listObj->observers_.erase(tmp);
445             } else {
446                 iter++;
447             }
448         }
449     }
450     for (auto observer : offObservers) {
451         if (!ObserverImpl::FindObserver(Uri(uri), observer)) {
452             LOGE("observer not exist");
453             ErrorHandler::Throw(env, E_PARAMS);
454             return;
455         }
456         sptr<ObserverImpl> obs = ObserverImpl::GetObserver(Uri(uri), observer);
457         if (obs == nullptr) {
458             LOGE("new observerimpl failed");
459             ErrorHandler::Throw(env, E_PARAMS);
460             return;
461         }
462         ErrCode ret = obsMgrClient->UnregisterObserverExt(Uri(uri), obs);
463         if (ret != ERR_OK) {
464             LOGE("call obs unregister fail");
465             ErrorHandler::Throw(env, E_PARAMS);
466             return;
467         }
468         ObserverImpl::DeleteObserver(Uri(uri), observer);
469     }
470 }
471 
UnRegisterChange(ani_env * env,ani_class clazz,ani_string uri)472 void CloudSyncAni::UnRegisterChange(ani_env *env, ani_class clazz, ani_string uri)
473 {
474     if (g_listObj == nullptr || g_listObj->observers_.empty()) {
475         LOGI("no obs to unregister");
476         return;
477     }
478 
479     std::string uriInput;
480     ani_status ret = ANIUtils::AniString2String(env, uri, uriInput);
481     if (ret != ANI_OK) {
482         ErrorHandler::Throw(env, E_PARAMS);
483         return;
484     }
485 
486     UnregisterFromObs(env, uriInput);
487 }
488 } // namespace OHOS::FileManagement::CloudSync