1 /*
2 * Copyright (c) 2024 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 "daemon_execute.h"
17 
18 #include <chrono>
19 #include <ctime>
20 #include <filesystem>
21 #include <memory>
22 #include <random>
23 #include <regex>
24 
25 #include "asset_callback_manager.h"
26 #include "dfs_error.h"
27 #include "network/softbus/softbus_asset_send_listener.h"
28 #include "network/softbus/softbus_handler_asset.h"
29 #include "network/softbus/softbus_session_pool.h"
30 #include "refbase.h"
31 #include "sandbox_helper.h"
32 #include "utils_directory.h"
33 #include "utils_log.h"
34 
35 #include "all_connect/all_connect_manager.h"
36 #include "network/softbus/softbus_handler.h"
37 
38 namespace OHOS {
39 namespace Storage {
40 namespace DistributedFile {
41 using namespace OHOS::AppFileService;
42 using namespace OHOS::FileManagement;
DaemonExecute()43 DaemonExecute::DaemonExecute()
44 {
45     LOGI("DaemonExecute begin.");
46     executeFuncMap_[DEAMON_EXECUTE_PUSH_ASSET] = &DaemonExecute::ExecutePushAsset;
47     executeFuncMap_[DEAMON_EXECUTE_REQUEST_SEND_FILE] = &DaemonExecute::ExecuteRequestSendFile;
48 }
49 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)50 void DaemonExecute::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
51 {
52     if (event == nullptr) {
53         LOGE("event is nullptr.");
54         return;
55     }
56     std::lock_guard<std::mutex> lock(executeFuncMapMutex_);
57     auto itFunc = executeFuncMap_.find(event->GetInnerEventId());
58     if (itFunc == executeFuncMap_.end()) {
59         LOGE("not find execute func.");
60         return;
61     }
62 
63     auto executeFunc = itFunc->second;
64     (this->*executeFunc)(event);
65 }
66 
ExecutePushAsset(const AppExecFwk::InnerEvent::Pointer &event)67 void DaemonExecute::ExecutePushAsset(const AppExecFwk::InnerEvent::Pointer &event)
68 {
69     if (event == nullptr) {
70         LOGI("eventhandler fail.");
71         return;
72     }
73     auto pushData = event->GetSharedObject<PushAssetData>();
74     if (pushData == nullptr) {
75         LOGE("pushData is nullptr.");
76         return;
77     }
78     int32_t userId = pushData->userId_;
79     auto assetObj = pushData->assetObj_;
80     if (assetObj == nullptr) {
81         LOGE("assetObj is nullptr.");
82         return;
83     }
84     int32_t socketId;
85     auto ret = SoftBusHandlerAsset::GetInstance().AssetBind(assetObj->dstNetworkId_, socketId);
86     if (ret != E_OK) {
87         LOGE("ExecutePushAsset AssetBind failed, ret %{public}d", ret);
88         auto taskId = assetObj->srcBundleName_ + assetObj->sessionId_;
89         AssetCallbackManager::GetInstance().NotifyAssetSendResult(taskId, assetObj, FileManagement::E_EVENT_HANDLER);
90         AssetCallbackManager::GetInstance().RemoveSendCallback(taskId);
91         return;
92     }
93     SoftBusHandlerAsset::GetInstance().AddAssetObj(socketId, assetObj);
94 
95     auto fileList = GetFileList(assetObj->uris_, userId, assetObj->srcBundleName_);
96     if (fileList.empty()) {
97         LOGE("get fileList is empty.");
98         HandlePushAssetFail(socketId, assetObj);
99         return;
100     }
101 
102     std::string sendFileName;
103     bool isSingleFile;
104     ret = HandleZip(fileList, assetObj, sendFileName, isSingleFile);
105     if (ret != E_OK) {
106         LOGE("zip files fail. socketId is %{public}d", socketId);
107         HandlePushAssetFail(socketId, assetObj);
108         SoftBusHandlerAsset::GetInstance().RemoveFile(sendFileName, !isSingleFile);
109         return;
110     }
111 
112     ret = SoftBusHandlerAsset::GetInstance().AssetSendFile(socketId, sendFileName, isSingleFile);
113     if (ret != E_OK) {
114         LOGE("ExecutePushAsset send file fail, ret %{public}d", ret);
115         HandlePushAssetFail(socketId, assetObj);
116         SoftBusHandlerAsset::GetInstance().RemoveFile(sendFileName, !isSingleFile);
117         return;
118     }
119 }
120 
ExecuteRequestSendFile(const AppExecFwk::InnerEvent::Pointer &event)121 void DaemonExecute::ExecuteRequestSendFile(const AppExecFwk::InnerEvent::Pointer &event)
122 {
123     if (event == nullptr) {
124         LOGI("eventhandler fail.");
125         return;
126     }
127     auto requestSendFileData = event->GetSharedObject<RequestSendFileData>();
128     if (requestSendFileData == nullptr) {
129         LOGE("requestSendFileData is nullptr.");
130         return;
131     }
132 
133     auto requestSendFileBlock  = requestSendFileData->requestSendFileBlock_;
134     if (requestSendFileBlock == nullptr) {
135         LOGE("requestSendFileBlock is nullptr.");
136         return;
137     }
138     std::string srcUri = requestSendFileData->srcUri_;
139     std::string dstPath  = requestSendFileData->dstPath_;
140     std::string dstDeviceId  = requestSendFileData->dstDeviceId_;
141     std::string sessionName  = requestSendFileData->sessionName_;
142     if (srcUri.empty() || dstDeviceId.empty() || sessionName.empty()) {
143         LOGE("params empty. %{public}s, %{public}s", sessionName.c_str(), Utils::GetAnonyString(dstDeviceId).c_str());
144         requestSendFileBlock->SetValue(ERR_BAD_VALUE);
145         return;
146     }
147 
148     requestSendFileBlock->SetValue(RequestSendFileInner(srcUri, dstPath, dstDeviceId, sessionName));
149 }
150 
RequestSendFileInner(const std::string &srcUri, const std::string &dstPath, const std::string &dstDeviceId, const std::string &sessionName)151 int32_t DaemonExecute::RequestSendFileInner(const std::string &srcUri,
152                                             const std::string &dstPath,
153                                             const std::string &dstDeviceId,
154                                             const std::string &sessionName)
155 {
156     LOGI("RequestSendFile begin dstDeviceId: %{public}s", Utils::GetAnonyString(dstDeviceId).c_str());
157     auto resourceReq = AllConnectManager::GetInstance().BuildResourceRequest();
158     int32_t ret = AllConnectManager::GetInstance().ApplyAdvancedResource(dstDeviceId, resourceReq.get());
159     if (ret != E_OK) {
160         LOGE("ApplyAdvancedResource fail, ret is %{public}d", ret);
161         return ERR_APPLY_RESULT;
162     }
163 
164     int32_t socketId;
165     ret = SoftBusHandler::GetInstance().OpenSession(sessionName, sessionName, dstDeviceId, socketId);
166     if (ret != E_OK) {
167         LOGE("OpenSession failed, ret is %{public}d", ret);
168         return ret;
169     }
170     AllConnectManager::GetInstance().PublishServiceState(dstDeviceId,
171                                                          ServiceCollaborationManagerBussinessStatus::SCM_CONNECTED);
172     LOGI("RequestSendFile OpenSession success");
173 
174     ret = SoftBusHandler::GetInstance().CopySendFile(socketId, sessionName, srcUri, dstPath);
175     if (ret != E_OK) {
176         LOGE("CopySendFile failed, ret is %{public}d", ret);
177         SoftBusHandler::GetInstance().CloseSession(socketId, sessionName);
178         return ret;
179     }
180     return E_OK;
181 }
182 
GetZipName(const std::string &relativePath)183 std::string DaemonExecute::GetZipName(const std::string &relativePath)
184 {
185     auto cppnow = std::chrono::system_clock::now();
186     auto cppnow_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(cppnow);
187     auto value = std::to_string(cppnow_ms.time_since_epoch().count());
188 
189     std::random_device rd;
190     std::string random = std::to_string(rd());
191     std::string zipName = value + "_" + random + ".zip";
192 
193     while (std::filesystem::exists(relativePath + zipName)) {
194         random = std::to_string(rd());
195         zipName = value + "_" + random + ".zip";
196     }
197     LOGI("zipName is %{public}s", zipName.c_str());
198     return zipName;
199 }
200 
GetFileList(const std::vector<std::string> &uris, int32_t userId, const std::string &srcBundleName)201 std::vector<std::string> DaemonExecute::GetFileList(const std::vector<std::string> &uris,
202                                                     int32_t userId,
203                                                     const std::string &srcBundleName)
204 {
205     std::vector<std::string> fileList;
206     std::regex pattern("/mnt/hmdfs/\\d{3,}/account/device_view/local/data/.*");
207     for (const auto &uri : uris) {
208         size_t pos = uri.find(srcBundleName);
209         if (pos == std::string::npos) {
210             LOGE("srcBundleName not find in uri.");
211             return {};
212         }
213 
214         std::string physicalPath;
215         int32_t ret = SandboxHelper::GetPhysicalPath(uri, std::to_string(userId), physicalPath);
216         if (ret != E_OK) {
217             LOGE("invalid uri, ret = %{public}d", ret);
218             return {};
219         }
220         if (!SandboxHelper::CheckValidPath(physicalPath)) {
221             LOGE("invalid path : %{public}s", GetAnonyString(physicalPath).c_str());
222             return {};
223         }
224         if (OHOS::Storage::DistributedFile::Utils::IsFolder(physicalPath)) {
225             LOGE("uri is folder are not supported now.");
226             return {};
227         }
228         if (!std::regex_match(physicalPath, pattern)) {
229             LOGE("physicalPath is not hmdfs path.");
230         }
231         fileList.emplace_back(physicalPath);
232     }
233     LOGI("GetFileList success, file num is %{public}s", std::to_string(fileList.size()).c_str());
234     return fileList;
235 }
236 
HandleZip(const std::vector<std::string> &fileList, const sptr<AssetObj> &assetObj, std::string &sendFileName, bool &isSingleFile)237 int32_t DaemonExecute::HandleZip(const std::vector<std::string> &fileList,
238                                  const sptr<AssetObj> &assetObj,
239                                  std::string &sendFileName,
240                                  bool &isSingleFile)
241 {
242     if (fileList.size() > 1) {
243         size_t pos = fileList[0].find(assetObj->srcBundleName_);
244         if (pos == std::string::npos) {
245             LOGE("srcBundleName not find in uri.");
246             return E_ZIP;
247         }
248         std::string relativePath = fileList[0].substr(0, pos + assetObj->srcBundleName_.length()) + "/";
249         sendFileName = relativePath + GetZipName(relativePath);
250         int32_t ret = SoftBusHandlerAsset::GetInstance().CompressFile(fileList, relativePath, sendFileName);
251         if (ret != E_OK) {
252             LOGE("zip ffiles fail.");
253             return E_ZIP;
254         }
255         isSingleFile = false;
256         SoftBusAssetSendListener::AddFileMap(assetObj->srcBundleName_ + assetObj->sessionId_, false);
257         return E_OK;
258     } else {
259         sendFileName = fileList[0];
260         isSingleFile = true;
261         SoftBusAssetSendListener::AddFileMap(assetObj->srcBundleName_ + assetObj->sessionId_, true);
262         return E_OK;
263     }
264 }
265 
HandlePushAssetFail(int32_t socketId, const sptr<AssetObj> &assetObj)266 void DaemonExecute::HandlePushAssetFail(int32_t socketId, const sptr<AssetObj> &assetObj)
267 {
268     auto taskId = assetObj->srcBundleName_ + assetObj->sessionId_;
269     AssetCallbackManager::GetInstance().NotifyAssetSendResult(taskId, assetObj, FileManagement::E_EVENT_HANDLER);
270     SoftBusHandlerAsset::GetInstance().closeAssetBind(socketId);
271     AssetCallbackManager::GetInstance().RemoveSendCallback(taskId);
272     SoftBusAssetSendListener::RemoveFileMap(taskId);
273 }
274 } // namespace DistributedFile
275 } // namespace Storage
276 } // namespace OHOS
277