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