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_download_ani.h"
17
18 #include "ani_utils.h"
19 #include "dfsu_access_token_helper.h"
20 #include "dfs_error.h"
21 #include "error_handler.h"
22 #include "utils_log.h"
23
24 namespace OHOS::FileManagement::CloudSync {
25 using namespace arkts::ani_signature;
26
CloudDownloadUnwrap(ani_env * env,ani_object object)27 static CloudFileCore *CloudDownloadUnwrap(ani_env *env, ani_object object)
28 {
29 ani_long nativePtr;
30 auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr);
31 if (ret != ANI_OK) {
32 LOGE("Unwrap cloudsyncCore err: %{public}d", static_cast<int32_t>(ret));
33 return nullptr;
34 }
35 std::uintptr_t ptrValue = static_cast<std::uintptr_t>(nativePtr);
36 CloudFileCore *cloudDownload = reinterpret_cast<CloudFileCore *>(ptrValue);
37 return cloudDownload;
38 }
39
CheckPermissions(const string & permission,bool isSystemApp)40 static int32_t CheckPermissions(const string &permission, bool isSystemApp)
41 {
42 if (!permission.empty() && !DfsuAccessTokenHelper::CheckCallerPermission(permission)) {
43 LOGE("permission denied");
44 return JsErrCode::E_PERMISSION;
45 }
46 if (isSystemApp && !DfsuAccessTokenHelper::IsSystemApp()) {
47 LOGE("caller hap is not system hap");
48 return JsErrCode::E_PERMISSION_SYS;
49 }
50 return E_OK;
51 }
52
DownloadConstructor(ani_env * env,ani_object object)53 void CloudDownloadAni::DownloadConstructor(ani_env *env, ani_object object)
54 {
55 ani_namespace ns {};
56 Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync");
57 ani_status ret = env->FindNamespace(nsSign.Descriptor().c_str(), &ns);
58 if (ret != ANI_OK) {
59 LOGE("find namespace failed. ret = %{public}d", static_cast<int32_t>(ret));
60 ErrorHandler::Throw(env, ENOMEM);
61 return;
62 }
63 Type clsName = Builder::BuildClass("Download");
64 ani_class cls;
65 ret = env->Namespace_FindClass(ns, clsName.Descriptor().c_str(), &cls);
66 if (ret != ANI_OK) {
67 LOGE("find class failed. ret = %{public}d", static_cast<int32_t>(ret));
68 ErrorHandler::Throw(env, ENOMEM);
69 return;
70 }
71
72 ani_method bindNativePtr;
73 std::string bindSign = Builder::BuildSignatureDescriptor({Builder::BuildLong()});
74 ret = env->Class_FindMethod(cls, "bindNativePtr", bindSign.c_str(), &bindNativePtr);
75 if (ret != ANI_OK) {
76 LOGE("find class ctor. ret = %{public}d", static_cast<int32_t>(ret));
77 ErrorHandler::Throw(env, ENOMEM);
78 return;
79 }
80
81 FsResult<CloudFileCore *> data = CloudFileCore::Constructor();
82 if (!data.IsSuccess()) {
83 LOGE("cloudfile constructor failed.");
84 const auto &err = data.GetError();
85 ErrorHandler::Throw(env, err);
86 return;
87 }
88
89 auto cloudFile = data.GetData().value();
90 ret = env->Object_CallMethod_Void(object, bindNativePtr, reinterpret_cast<ani_long>(cloudFile));
91 if (ret != ANI_OK) {
92 LOGE("bindNativePtr failed.");
93 ErrorHandler::Throw(env, ENOMEM);
94 delete cloudFile;
95 }
96 }
97
DownloadOn(ani_env * env,ani_object object,ani_string evt,ani_object fun)98 void CloudDownloadAni::DownloadOn(ani_env *env, ani_object object, ani_string evt, ani_object fun)
99 {
100 std::string event;
101 ani_status ret = ANIUtils::AniString2String(env, evt, event);
102 if (ret != ANI_OK) {
103 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
104 return;
105 }
106 if (event != "progress") {
107 LOGE("Invalid argument for event type.");
108 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
109 return;
110 }
111
112 int32_t res = CheckPermissions(PERM_CLOUD_SYNC, true);
113 if (res != E_OK) {
114 LOGE("On get progress failed!");
115 ErrorHandler::Throw(env, res);
116 return;
117 }
118
119 auto cloudDownload = CloudDownloadUnwrap(env, object);
120 if (cloudDownload == nullptr) {
121 LOGE("Cannot wrap cloudDownload.");
122 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
123 return;
124 }
125
126 std::shared_ptr<CloudDownloadCallbackImplAni> callbackImpl = cloudDownload->GetCallbackImpl(true);
127 callbackImpl->InitVm(env);
128 auto status = callbackImpl->RegisterCallback(env, fun);
129 if (status != ANI_OK) {
130 LOGE("Failed to register callback, status: %{public}d.", status);
131 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
132 return;
133 }
134 }
135
DownloadOff0(ani_env * env,ani_object object,ani_string evt,ani_object fun)136 void CloudDownloadAni::DownloadOff0(ani_env *env, ani_object object, ani_string evt, ani_object fun)
137 {
138 std::string event;
139 ani_status ret = ANIUtils::AniString2String(env, evt, event);
140 if (ret != ANI_OK) {
141 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
142 return;
143 }
144 if (event != "progress") {
145 LOGE("Invalid argument for event type.");
146 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
147 return;
148 }
149
150 int32_t res = CheckPermissions(PERM_CLOUD_SYNC, true);
151 if (res != E_OK) {
152 LOGE("On get progress failed!");
153 ErrorHandler::Throw(env, res);
154 return;
155 }
156
157 auto cloudDownload = CloudDownloadUnwrap(env, object);
158 if (cloudDownload == nullptr) {
159 LOGE("Cannot wrap cloudDownload.");
160 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
161 return;
162 }
163
164 std::shared_ptr<CloudDownloadCallbackImplAni> callbackImpl = cloudDownload->GetCallbackImpl(false);
165 if (callbackImpl == nullptr || callbackImpl->UnregisterCallback(env, fun) != ANI_OK) {
166 LOGE("Failed to unregister callback");
167 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
168 return;
169 }
170 }
171
DownloadOff1(ani_env * env,ani_object object,ani_string evt)172 void CloudDownloadAni::DownloadOff1(ani_env *env, ani_object object, ani_string evt)
173 {
174 DownloadOff0(env, object, evt, nullptr);
175 }
176
DownloadStart(ani_env * env,ani_object object,ani_string uri)177 void CloudDownloadAni::DownloadStart(ani_env *env, ani_object object, ani_string uri)
178 {
179 std::string uriInput;
180 ani_status ret = ANIUtils::AniString2String(env, uri, uriInput);
181 if (ret != ANI_OK) {
182 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
183 return;
184 }
185
186 auto cloudDownload = CloudDownloadUnwrap(env, object);
187 if (cloudDownload == nullptr) {
188 LOGE("Cannot wrap cloudDownload.");
189 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
190 return;
191 }
192 std::shared_ptr<CloudDownloadCallbackImplAni> callbackImpl = cloudDownload->GetCallbackImpl(true);
193 callbackImpl->InitVm(env);
194 auto data = cloudDownload->DoStart(uriInput);
195 if (!data.IsSuccess()) {
196 const auto &err = data.GetError();
197 LOGE("cloud download do start failed, ret = %{public}d", err.GetErrNo());
198 ErrorHandler::Throw(env, err);
199 }
200 }
201
DownloadStop(ani_env * env,ani_object object,ani_string uri)202 void CloudDownloadAni::DownloadStop(ani_env *env, ani_object object, ani_string uri)
203 {
204 std::string uriInput;
205 ani_status ret = ANIUtils::AniString2String(env, uri, uriInput);
206 if (ret != ANI_OK) {
207 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
208 return;
209 }
210
211 auto cloudDownload = CloudDownloadUnwrap(env, object);
212 if (cloudDownload == nullptr) {
213 LOGE("Cannot wrap cloudDownload.");
214 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
215 return;
216 }
217 std::shared_ptr<CloudDownloadCallbackImplAni> callbackImpl = cloudDownload->GetCallbackImpl(false);
218 if (callbackImpl == nullptr) {
219 LOGE("Cannot get callbackImpl before stop.");
220 ErrorHandler::Throw(env, JsErrCode::E_IPCSS);
221 return;
222 }
223
224 auto data = cloudDownload->DoStop(uriInput);
225 if (!data.IsSuccess()) {
226 const auto &err = data.GetError();
227 LOGE("cloud download do stop failed, ret = %{public}d", err.GetErrNo());
228 ErrorHandler::Throw(env, err);
229 }
230 }
231 } // namespace OHOS::FileManagement::CloudSync