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