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 ®isterParams)
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 ®isterParams)
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), ®isterParams.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