• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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