1 /*
2 * Copyright (c) 2023 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 <filesystem>
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 auto ret = sessionManager_->SendData(networkId, data.get(), dataLen);
60 if (ret != E_OK) {
61 LOGE("download file failed, uri:%{public}s, ret:%{public}d", uri.c_str(), ret);
62 DownloadAssetCallbackManager::GetInstance().OnDownloadFinshed(taskId, uri, ret);
63 DecTransTaskCount();
64 } else {
65 AddTransTask(uri, userId, taskId);
66 }
67 }
68
HandleDownloadFileRequest(MessageHandler & msgHandler,const std::string & senderNetworkId,int receiverSessionId)69 void FileTransferManager::HandleDownloadFileRequest(MessageHandler &msgHandler,
70 const std::string &senderNetworkId,
71 int receiverSessionId)
72 {
73 IncTransTaskCount();
74 auto uri = msgHandler.GetUri();
75 auto userId = msgHandler.GetUserId();
76 auto [physicalPath, relativePath] = UriToPath(uri, userId);
77 uint32_t errorCode = E_OK;
78 if (!relativePath.empty()) {
79 auto result = sessionManager_->SendFile(senderNetworkId, {physicalPath}, {relativePath});
80 if (result != E_OK) {
81 LOGE("send file failed, relativePath:%{public}s, ret:%{public}d", relativePath.c_str(), result);
82 errorCode = E_SEND_FILE;
83 DecTransTaskCount();
84 }
85 } else {
86 errorCode = E_FILE_NOT_EXIST;
87 DecTransTaskCount();
88 }
89 auto taskId = msgHandler.GetTaskId();
90 MessageInputInfo info = {.srcNetworkId = "",
91 .dstNetworkId = senderNetworkId,
92 .uri = uri,
93 .msgType = MSG_DOWNLOAD_FILE_RSP,
94 .errorCode = errorCode,
95 .userId = userId,
96 .taskId = taskId};
97 MessageHandler resp(info);
98 uint32_t dataLen = resp.GetDataSize();
99 auto data = make_unique<uint8_t[]>(dataLen);
100 resp.PackData(data.get(), dataLen);
101 auto ret = sessionManager_->SendData(receiverSessionId, data.get(), dataLen);
102 if (ret != E_OK) {
103 LOGE("response failed: %{public}d, sessionId:%{public}d", ret, receiverSessionId);
104 }
105 LOGD("send response, sessionId:%{public}d", receiverSessionId);
106 }
107
HandleDownloadFileResponse(MessageHandler & msgHandler)108 void FileTransferManager::HandleDownloadFileResponse(MessageHandler &msgHandler)
109 {
110 LOGD("recviceve response msg");
111 auto errorCode = msgHandler.GetErrorCode();
112 if (errorCode == E_OK) {
113 LOGD("callback after file recv finished");
114 return;
115 }
116 auto uri = msgHandler.GetUri();
117 auto taskId = msgHandler.GetTaskId();
118 DownloadAssetCallbackManager::GetInstance().OnDownloadFinshed(taskId, uri, errorCode);
119 DecTransTaskCount();
120 RemoveTransTask(taskId);
121 }
122
HandleRecvFileFinished()123 void FileTransferManager::HandleRecvFileFinished()
124 {
125 LOGI("file transfer finished");
126 DecTransTaskCount(); // task finished, may be can unload sa
127 }
128
OnMessageHandle(const std::string & senderNetworkId,int receiverSessionId,const void * data,unsigned int dataLen)129 void FileTransferManager::OnMessageHandle(const std::string &senderNetworkId,
130 int receiverSessionId,
131 const void *data,
132 unsigned int dataLen)
133 {
134 MessageHandler msgHandler;
135 bool ret = msgHandler.UnPackData((uint8_t *)data, dataLen);
136 if (!ret) {
137 LOGE("package data invalid");
138 return;
139 }
140 auto msgType = msgHandler.GetMsgType();
141 if (msgType == MSG_DOWNLOAD_FILE_REQ) {
142 HandleDownloadFileRequest(msgHandler, senderNetworkId, receiverSessionId);
143 } else if (msgType == MSG_DOWNLOAD_FILE_RSP) {
144 HandleDownloadFileResponse(msgHandler);
145 } else if (msgType == MSG_FINISH_FILE_RECV) {
146 HandleRecvFileFinished();
147 } else {
148 LOGE("error msg type:%{public}d", msgType);
149 }
150 }
151
OnFileRecvHandle(const std::string & senderNetworkId,const char * filePath,int result)152 void FileTransferManager::OnFileRecvHandle(const std::string &senderNetworkId, const char *filePath, int result)
153 {
154 LOGE("received file, file path:%{public}s, result:%{public}d", filePath, result);
155 DecTransTaskCount(); // allways dec task count when finsh one task
156 if (filePath != nullptr) {
157 FinishTransTask(string(filePath), result);
158 }
159
160 MessageInputInfo info = {.msgType = MSG_FINISH_FILE_RECV};
161 MessageHandler req(info);
162 uint32_t dataLen = req.GetDataSize();
163 auto data = make_unique<uint8_t[]>(dataLen);
164 req.PackData(data.get(), dataLen);
165 auto ret = sessionManager_->SendData(senderNetworkId, data.get(), dataLen);
166 if (ret != E_OK) {
167 LOGE("response failed: %{public}d", ret);
168 }
169 LOGI("send file recv finished msg");
170 }
171
OnSessionClosed()172 void FileTransferManager::OnSessionClosed() // avoid sa cannot unload when session disconnect
173 {
174 taskCount_.store(0);
175 TaskStateManager::GetInstance().CompleteTask(CALLER_NAME, TaskType::DOWNLOAD_REMOTE_ASSET_TASK);
176 }
177
IsFileExists(std::string & filePath)178 bool FileTransferManager::IsFileExists(std::string &filePath)
179 {
180 if (filesystem::exists(filePath)) {
181 return true;
182 } else {
183 return false;
184 }
185 }
186
UriToPath(const std::string & uri,const int32_t userId,bool isCheckFileExists)187 std::tuple<std::string, std::string> FileTransferManager::UriToPath(const std::string &uri,
188 const int32_t userId,
189 bool isCheckFileExists)
190 {
191 string physicalPath = "";
192 int ret = AppFileService::SandboxHelper::GetPhysicalPath(uri, std::to_string(userId), physicalPath);
193 if (ret != 0) {
194 LOGE("Get physical path failed with %{public}d", ret);
195 return {"", ""};
196 }
197
198 if (isCheckFileExists) {
199 if (!this->IsFileExists(physicalPath)) {
200 return {"", ""};
201 }
202 }
203
204 const string HMDFS_DIR = "/mnt/hmdfs/";
205 const string DATA_DIR = HMDFS_DIR + to_string(userId) + "/account/device_view/local/data";
206
207 std::string relativePath;
208 size_t fileDirPos = physicalPath.find(DATA_DIR);
209 if (fileDirPos == std::string::npos) {
210 return {"", ""};
211 }
212 fileDirPos += DATA_DIR.length();
213 relativePath = physicalPath.substr(fileDirPos);
214
215 return {physicalPath, relativePath};
216 }
217
AddTransTask(const std::string & uri,const int32_t userId,uint64_t taskId)218 void FileTransferManager::AddTransTask(const std::string &uri, const int32_t userId, uint64_t taskId)
219 {
220 lock_guard<mutex> lock(taskMutex_);
221 auto [physicalPath, relativePath] = UriToPath(uri, userId, false);
222 TaskInfo info = {uri, relativePath, taskId};
223 taskInfos_.push_back(info);
224 }
225
RemoveTransTask(uint64_t taskId)226 void FileTransferManager::RemoveTransTask(uint64_t taskId)
227 {
228 LOGI("remove task:%{public}" PRIu64 "", taskId);
229 lock_guard<mutex> lock(taskMutex_);
230 for (auto iter = taskInfos_.begin(); iter != taskInfos_.end();) {
231 if ((*iter).taskId == taskId) {
232 iter = taskInfos_.erase(iter);
233 } else {
234 ++iter;
235 }
236 }
237 }
238
FinishTransTask(const std::string & relativePath,int result)239 void FileTransferManager::FinishTransTask(const std::string &relativePath, int result)
240 {
241 lock_guard<mutex> lock(taskMutex_);
242 for (auto iter = taskInfos_.begin(); iter != taskInfos_.end();) {
243 if ((*iter).relativePath == relativePath) {
244 DownloadAssetCallbackManager::GetInstance().OnDownloadFinshed((*iter).taskId, (*iter).uri, result);
245 iter = taskInfos_.erase(iter);
246 return; // match the first one
247 } else {
248 ++iter;
249 }
250 }
251 LOGE("not found task, relativePath:%{public}s", relativePath.c_str());
252 }
253
IncTransTaskCount()254 void FileTransferManager::IncTransTaskCount()
255 {
256 TaskStateManager::GetInstance().StartTask(CALLER_NAME, TaskType::DOWNLOAD_REMOTE_ASSET_TASK);
257 taskCount_.fetch_add(1);
258 }
259
DecTransTaskCount()260 void FileTransferManager::DecTransTaskCount()
261 {
262 auto count = taskCount_.fetch_sub(1);
263 if (count == 1) {
264 TaskStateManager::GetInstance().CompleteTask(CALLER_NAME, TaskType::DOWNLOAD_REMOTE_ASSET_TASK);
265 } else if (count < 1) {
266 taskCount_.store(0);
267 }
268 }
269 } // namespace OHOS::FileManagement::CloudSync
270