1 /*
2 * Copyright (c) 2023-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 "file_transfer_manager.h"
17
18 #include <cinttypes>
19 #include <unistd.h>
20
21 #include "dfs_error.h"
22 #include "ipc/download_asset_callback_manager.h"
23 #include "sandbox_helper.h"
24 #include "task_state_manager.h"
25 #include "utils_log.h"
26
27 namespace OHOS::FileManagement::CloudSync {
28 using namespace std;
29 static const string CALLER_NAME = "distributeddata";
30
FileTransferManager(std::shared_ptr<SessionManager> sessionManager)31 FileTransferManager::FileTransferManager(std::shared_ptr<SessionManager> sessionManager)
32 : sessionManager_(sessionManager)
33 {
34 }
35
Init()36 void FileTransferManager::Init()
37 {
38 sessionManager_->RegisterDataHandler(shared_from_this());
39 }
40
DownloadFileFromRemoteDevice(const std::string & networkId,const int32_t userId,const uint64_t taskId,const std::string & uri)41 void FileTransferManager::DownloadFileFromRemoteDevice(const std::string &networkId,
42 const int32_t userId,
43 const uint64_t taskId,
44 const std::string &uri)
45 {
46 IncTransTaskCount();
47 MessageInputInfo info = {.srcNetworkId = "",
48 .dstNetworkId = networkId,
49 .uri = uri,
50 .msgType = MSG_DOWNLOAD_FILE_REQ,
51 .errorCode = 0,
52 .userId = userId,
53 .taskId = taskId};
54 MessageHandler msgHandler(info);
55 uint32_t dataLen = msgHandler.GetDataSize();
56 auto data = make_unique<uint8_t[]>(dataLen);
57 msgHandler.PackData(data.get(), dataLen);
58 LOGI("send data, dataLen:%{public}d, taskId: %{public}" PRIu64 "", dataLen, taskId);
59 std::string bundleName = GetBundleNameForUri(uri);
60 if (bundleName.empty()) {
61 return;
62 }
63 sessionManager_->SetFileRecvPath(bundleName, userId);
64 auto ret = sessionManager_->SendData(networkId, data.get(), dataLen);
65 if (ret != E_OK) {
66 LOGE("download file failed, uri:%{public}s, ret:%{public}d", GetAnonyString(uri).c_str(), ret);
67 DownloadAssetCallbackManager::GetInstance().OnDownloadFinshed(taskId, uri, ret);
68 DecTransTaskCount();
69 } else {
70 AddTransTask(uri, userId, taskId);
71 }
72 }
73
HandleDownloadFileRequest(MessageHandler & msgHandler,const std::string & senderNetworkId,int receiverSessionId)74 void FileTransferManager::HandleDownloadFileRequest(MessageHandler &msgHandler,
75 const std::string &senderNetworkId,
76 int receiverSessionId)
77 {
78 IncTransTaskCount();
79 auto uri = msgHandler.GetUri();
80 auto userId = msgHandler.GetUserId();
81 auto [physicalPath, relativePath] = UriToPath(uri, userId);
82 uint32_t errorCode = E_OK;
83 if (!relativePath.empty()) {
84 auto result = sessionManager_->SendFile(senderNetworkId, {physicalPath}, {relativePath});
85 if (result != E_OK) {
86 LOGE("send file failed, relativePath:%{public}s, ret:%{public}d",
87 GetAnonyString(relativePath).c_str(), result);
88 errorCode = E_SEND_FILE;
89 DecTransTaskCount();
90 }
91 } else {
92 errorCode = E_FILE_NOT_EXIST;
93 DecTransTaskCount();
94 }
95 auto taskId = msgHandler.GetTaskId();
96 MessageInputInfo info = {.srcNetworkId = "",
97 .dstNetworkId = senderNetworkId,
98 .uri = uri,
99 .msgType = MSG_DOWNLOAD_FILE_RSP,
100 .errorCode = errorCode,
101 .userId = userId,
102 .taskId = taskId};
103 MessageHandler resp(info);
104 uint32_t dataLen = resp.GetDataSize();
105 auto data = make_unique<uint8_t[]>(dataLen);
106 resp.PackData(data.get(), dataLen);
107 auto ret = sessionManager_->SendData(receiverSessionId, data.get(), dataLen);
108 if (ret != E_OK) {
109 LOGE("response failed: %{public}d, sessionId:%{public}d", ret, receiverSessionId);
110 }
111 LOGD("send response, sessionId:%{public}d", receiverSessionId);
112 }
113
HandleDownloadFileResponse(MessageHandler & msgHandler)114 void FileTransferManager::HandleDownloadFileResponse(MessageHandler &msgHandler)
115 {
116 LOGD("recviceve response msg");
117 auto errorCode = msgHandler.GetErrorCode();
118 if (errorCode != E_OK) {
119 LOGI("callback after file recv failed, errorCode:%{public}d", errorCode);
120 }
121 auto uri = msgHandler.GetUri();
122 auto taskId = msgHandler.GetTaskId();
123 DownloadAssetCallbackManager::GetInstance().OnDownloadFinshed(taskId, uri, errorCode);
124 DecTransTaskCount();
125 RemoveTransTask(taskId);
126 }
127
HandleRecvFileFinished()128 void FileTransferManager::HandleRecvFileFinished()
129 {
130 LOGI("file transfer finished");
131 DecTransTaskCount(); // task finished, may be can unload sa
132 }
133
OnMessageHandle(const std::string & senderNetworkId,int receiverSessionId,const void * data,unsigned int dataLen)134 void FileTransferManager::OnMessageHandle(const std::string &senderNetworkId,
135 int receiverSessionId,
136 const void *data,
137 unsigned int dataLen)
138 {
139 MessageHandler msgHandler;
140 bool ret = msgHandler.UnPackData((uint8_t *)data, dataLen);
141 if (!ret) {
142 LOGE("package data invalid");
143 return;
144 }
145 auto msgType = msgHandler.GetMsgType();
146 if (msgType == MSG_DOWNLOAD_FILE_REQ) {
147 HandleDownloadFileRequest(msgHandler, senderNetworkId, receiverSessionId);
148 } else if (msgType == MSG_DOWNLOAD_FILE_RSP) {
149 HandleDownloadFileResponse(msgHandler);
150 } else if (msgType == MSG_FINISH_FILE_RECV) {
151 HandleRecvFileFinished();
152 } else {
153 LOGE("error msg type:%{public}d", msgType);
154 }
155 }
156
OnFileRecvHandle(const std::string & senderNetworkId,const char * filePath,int result)157 void FileTransferManager::OnFileRecvHandle(const std::string &senderNetworkId, const char *filePath, int result)
158 {
159 LOGE("received file, file path:%{public}s, result:%{public}d", GetAnonyString(filePath).c_str(), result);
160 DecTransTaskCount(); // allways dec task count when finsh one task
161 if (filePath != nullptr) {
162 FinishTransTask(string(filePath), result);
163 }
164
165 MessageInputInfo info = {.msgType = MSG_FINISH_FILE_RECV};
166 MessageHandler req(info);
167 uint32_t dataLen = req.GetDataSize();
168 auto data = make_unique<uint8_t[]>(dataLen);
169 req.PackData(data.get(), dataLen);
170 auto ret = sessionManager_->SendData(senderNetworkId, data.get(), dataLen);
171 if (ret != E_OK) {
172 LOGE("response failed: %{public}d", ret);
173 }
174 LOGI("send file recv finished msg");
175 }
176
OnSessionClosed()177 void FileTransferManager::OnSessionClosed() // avoid sa cannot unload when session disconnect
178 {
179 taskCount_.store(0);
180 TaskStateManager::GetInstance().CompleteTask(CALLER_NAME, TaskType::DOWNLOAD_REMOTE_ASSET_TASK);
181 }
182
IsFileExists(const std::string & filePath)183 bool FileTransferManager::IsFileExists(const std::string &filePath)
184 {
185 if (access(filePath.c_str(), F_OK) != E_OK) {
186 LOGE("file is not exist, path:%{public}s, error:%{public}s", GetAnonyString(filePath).c_str(), strerror(errno));
187 return false;
188 }
189 return true;
190 }
191
GetBundleNameForUri(const std::string & uri)192 std::string FileTransferManager::GetBundleNameForUri(const std::string &uri)
193 {
194 static std::string uriHead = "file://";
195 auto pos = uri.find(uriHead);
196 if (pos != 0) {
197 LOGE("Invalid uri: %{public}s", GetAnonyString(uri).c_str());
198 return "";
199 }
200 auto length = uriHead.length();
201 pos = uri.find('/', length);
202 if (pos == std::string::npos) {
203 LOGE("Failed to get bundleName from uri: %{public}s", GetAnonyString(uri).c_str());
204 return "";
205 }
206 std::string path = uri.substr(length);
207 std::string bundleName = path.substr(0, pos - length);
208 return bundleName;
209 }
210
UriToPath(const std::string & uri,const int32_t userId,bool isCheckFileExists)211 std::tuple<std::string, std::string> FileTransferManager::UriToPath(const std::string &uri,
212 const int32_t userId,
213 bool isCheckFileExists)
214 {
215 string physicalPath = "";
216 int ret = AppFileService::SandboxHelper::GetPhysicalPath(uri, std::to_string(userId), physicalPath);
217 if (ret != 0 || !AppFileService::SandboxHelper::IsValidPath(physicalPath)) {
218 LOGE("Get physical path failed with %{public}d", ret);
219 return {"", ""};
220 }
221
222 if (isCheckFileExists) {
223 if (!this->IsFileExists(physicalPath)) {
224 return {"", ""};
225 }
226 }
227
228 const string HMDFS_DIR = "/mnt/hmdfs/";
229 const string DATA_DIR = HMDFS_DIR + to_string(userId) + "/account/device_view/local/data/";
230 size_t fileDirPos = physicalPath.find(DATA_DIR);
231 if (fileDirPos != 0) {
232 LOGE("Invalid physical path: %{public}s", GetAnonyString(physicalPath).c_str());
233 return {"", ""};
234 }
235 fileDirPos = physicalPath.find('/', DATA_DIR.length());
236 if (fileDirPos == std::string::npos) {
237 LOGE("Failed to get relative path, physical path: %{public}s", GetAnonyString(physicalPath).c_str());
238 return {"", ""};
239 }
240
241 std::string relativePath = physicalPath.substr(fileDirPos);
242 return {physicalPath, relativePath};
243 }
244
AddTransTask(const std::string & uri,const int32_t userId,uint64_t taskId)245 void FileTransferManager::AddTransTask(const std::string &uri, const int32_t userId, uint64_t taskId)
246 {
247 lock_guard<mutex> lock(taskMutex_);
248 auto [physicalPath, relativePath] = UriToPath(uri, userId, false);
249 TaskInfo info = {uri, relativePath, taskId};
250 taskInfos_.push_back(info);
251 }
252
RemoveTransTask(uint64_t taskId)253 void FileTransferManager::RemoveTransTask(uint64_t taskId)
254 {
255 LOGI("remove task:%{public}" PRIu64 "", taskId);
256 lock_guard<mutex> lock(taskMutex_);
257 for (auto iter = taskInfos_.begin(); iter != taskInfos_.end();) {
258 if ((*iter).taskId == taskId) {
259 iter = taskInfos_.erase(iter);
260 } else {
261 ++iter;
262 }
263 }
264 }
265
FinishTransTask(const std::string & relativePath,int result)266 void FileTransferManager::FinishTransTask(const std::string &relativePath, int result)
267 {
268 lock_guard<mutex> lock(taskMutex_);
269 for (auto iter = taskInfos_.begin(); iter != taskInfos_.end();) {
270 if ((*iter).relativePath == relativePath) {
271 DownloadAssetCallbackManager::GetInstance().OnDownloadFinshed((*iter).taskId, (*iter).uri, result);
272 iter = taskInfos_.erase(iter);
273 return; // match the first one
274 } else {
275 ++iter;
276 }
277 }
278 LOGE("not found task, relativePath:%{public}s", GetAnonyString(relativePath).c_str());
279 }
280
IncTransTaskCount()281 void FileTransferManager::IncTransTaskCount()
282 {
283 TaskStateManager::GetInstance().StartTask(CALLER_NAME, TaskType::DOWNLOAD_REMOTE_ASSET_TASK);
284 taskCount_.fetch_add(1);
285 }
286
DecTransTaskCount()287 void FileTransferManager::DecTransTaskCount()
288 {
289 auto count = taskCount_.fetch_sub(1);
290 if (count == 1) {
291 TaskStateManager::GetInstance().CompleteTask(CALLER_NAME, TaskType::DOWNLOAD_REMOTE_ASSET_TASK);
292 } else if (count < 1) {
293 taskCount_.store(0);
294 }
295 }
296 } // namespace OHOS::FileManagement::CloudSync
297