1 /*
2 * Copyright (c) 2021-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 "ipc/daemon.h"
17
18 #include <exception>
19 #include <stdexcept>
20
21 #include "accesstoken_kit.h"
22 #include "common_event_manager.h"
23 #include "common_event_support.h"
24 #include "connection_detector.h"
25 #include "device/device_manager_agent.h"
26 #include "dfs_error.h"
27 #include "ipc_skeleton.h"
28 #include "iremote_object.h"
29 #include "iservice_registry.h"
30 #include "mountpoint/mount_manager.h"
31 #include "network/softbus/softbus_handler.h"
32 #include "network/softbus/softbus_session_dispatcher.h"
33 #include "network/softbus/softbus_session_pool.h"
34 #include "network/softbus/softbus_session_listener.h"
35 #include "sandbox_helper.h"
36 #include "system_ability_definition.h"
37 #include "trans_mananger.h"
38 #include "utils_log.h"
39
40 namespace OHOS {
41 namespace Storage {
42 namespace DistributedFile {
43 using namespace std;
44 using namespace OHOS::AppFileService;
45 using namespace OHOS::FileManagement;
46 using HapTokenInfo = OHOS::Security::AccessToken::HapTokenInfo;
47 using AccessTokenKit = OHOS::Security::AccessToken::AccessTokenKit;
48
49 constexpr int32_t LINK_TYPE_NUM = 4;
50 const string FILE_MANAGER_AUTHORITY = "docs";
51 const string MEDIA_AUTHORITY = "media";
52 REGISTER_SYSTEM_ABILITY_BY_ID(Daemon, FILEMANAGEMENT_DISTRIBUTED_FILE_DAEMON_SA_ID, true);
53
PublishSA()54 void Daemon::PublishSA()
55 {
56 LOGI("Begin to init");
57 if (!registerToService_) {
58 bool ret = SystemAbility::Publish(this);
59 if (!ret) {
60 throw runtime_error("Failed to publish the daemon");
61 }
62 registerToService_ = true;
63 }
64 LOGI("Init finished successfully");
65 }
66
RegisterOsAccount()67 void Daemon::RegisterOsAccount()
68 {
69 EventFwk::MatchingSkills matchingSkills;
70 matchingSkills.AddEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USER_SWITCHED);
71 EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills);
72 subScriber_ = std::make_shared<OsAccountObserver>(subscribeInfo);
73 bool subRet = EventFwk::CommonEventManager::SubscribeCommonEvent(subScriber_);
74 if (!subRet) {
75 LOGE("Subscribe common event failed");
76 }
77 }
78
OnStart()79 void Daemon::OnStart()
80 {
81 LOGI("Begin to start service");
82 if (state_ == ServiceRunningState::STATE_RUNNING) {
83 LOGD("Daemon has already started");
84 return;
85 }
86
87 try {
88 PublishSA();
89 AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID);
90 } catch (const exception &e) {
91 LOGE("%{public}s", e.what());
92 }
93
94 state_ = ServiceRunningState::STATE_RUNNING;
95 LOGI("Start service successfully");
96 }
97
OnStop()98 void Daemon::OnStop()
99 {
100 LOGI("Begin to stop");
101 state_ = ServiceRunningState::STATE_NOT_START;
102 registerToService_ = false;
103 bool subRet = EventFwk::CommonEventManager::UnSubscribeCommonEvent(subScriber_);
104 if (!subRet) {
105 LOGE("UnSubscribe common event failed");
106 }
107 subScriber_ = nullptr;
108 LOGI("Stop finished successfully");
109 }
110
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)111 void Daemon::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
112 {
113 (void)systemAbilityId;
114 (void)deviceId;
115 RegisterOsAccount();
116 }
117
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)118 void Daemon::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
119 {
120 (void)deviceId;
121 if (systemAbilityId != COMMON_EVENT_SERVICE_ID) {
122 LOGE("systemAbilityId is not COMMON_EVENT_SERVICE_ID");
123 return;
124 }
125
126 if (subScriber_ == nullptr) {
127 LOGE("Daemon::OnRemoveSystemAbility subscriberPtr is nullptr");
128 return;
129 }
130
131 bool subscribeResult = EventFwk::CommonEventManager::UnSubscribeCommonEvent(subScriber_);
132 LOGI("Daemon::OnRemoveSystemAbility subscribeResult = %{public}d", subscribeResult);
133 subScriber_ = nullptr;
134 }
135
OpenP2PConnection(const DistributedHardware::DmDeviceInfo & deviceInfo)136 int32_t Daemon::OpenP2PConnection(const DistributedHardware::DmDeviceInfo &deviceInfo)
137 {
138 auto path = ConnectionDetector::ParseHmdfsPath();
139 stringstream ss;
140 ss << ConnectionDetector::MocklispHash(path);
141 auto targetDir = ss.str();
142 auto networkId = std::string(deviceInfo.networkId);
143 int32_t ret = 0;
144 if (!ConnectionDetector::GetConnectionStatus(targetDir, networkId)) {
145 LOGI("Get connection status not ok, try again.");
146 ret = DeviceManagerAgent::GetInstance()->OnDeviceP2POnline(deviceInfo);
147 if (ret != NO_ERROR) {
148 LOGE("OpenP2PConnection failed, ret = %{public}d", ret);
149 } else {
150 ret = ConnectionDetector::RepeatGetConnectionStatus(targetDir, networkId);
151 LOGI("RepeatGetConnectionStatus end, ret = %{public}d", ret);
152 }
153 }
154 return ret;
155 }
156
CloseP2PConnection(const DistributedHardware::DmDeviceInfo & deviceInfo)157 int32_t Daemon::CloseP2PConnection(const DistributedHardware::DmDeviceInfo &deviceInfo)
158 {
159 LOGI("Close P2P Connection");
160 std::thread([=]() {
161 int32_t ret = DeviceManagerAgent::GetInstance()->OnDeviceP2POffline(deviceInfo);
162 LOGI("Close P2P Connection result %d", ret);
163 return ret;
164 }).detach();
165 return 0;
166 }
167
RequestSendFile(const std::string & srcUri,const std::string & dstPath,const std::string & dstDeviceId,const std::string & sessionName)168 int32_t Daemon::RequestSendFile(const std::string &srcUri,
169 const std::string &dstPath,
170 const std::string &dstDeviceId,
171 const std::string &sessionName)
172 {
173 auto ret = SoftBusHandler::GetInstance().CreateSessionServer(IDaemon::SERVICE_NAME.c_str(), sessionName.c_str());
174 if (ret != E_OK) {
175 LOGE("CreateSessionServer failed, ret = %{public}d", ret);
176 return E_SOFTBUS_SESSION_FAILED;
177 }
178
179 ret = SoftBusHandler::GetInstance().SetFileSendListener(IDaemon::SERVICE_NAME.c_str(), sessionName.c_str());
180 if (ret != E_OK) {
181 LOGE("SetFileSendListener failed, ret = %{public}d", ret);
182 RemoveSessionServer(IDaemon::SERVICE_NAME.c_str(), sessionName.c_str());
183 return E_SOFTBUS_SESSION_FAILED;
184 }
185
186 SessionAttribute attr{
187 .dataType = TYPE_FILE,
188 .linkTypeNum = LINK_TYPE_NUM,
189 .linkType{LINK_TYPE_WIFI_P2P, LINK_TYPE_WIFI_WLAN_5G, LINK_TYPE_WIFI_WLAN_2G, LINK_TYPE_BR},
190 .fastTransData = nullptr,
191 .fastTransDataSize = 0,
192 };
193 auto sessionId = ::OpenSession(sessionName.c_str(), sessionName.c_str(), dstDeviceId.c_str(), "groupId", &attr);
194 if (sessionId <= 0) {
195 LOGE("OpenSession failed");
196 return E_SOFTBUS_SESSION_FAILED;
197 }
198
199 SoftBusSessionPool::SessionInfo sessionInfo{.sessionId = sessionId, .srcUri = srcUri, .dstPath = dstPath};
200 SoftBusSessionPool::GetInstance().AddSessionInfo(sessionName, sessionInfo);
201 return E_OK;
202 }
203
PrepareSession(const std::string & srcUri,const std::string & dstUri,const std::string & srcDeviceId,const sptr<IRemoteObject> & listener)204 int32_t Daemon::PrepareSession(const std::string &srcUri,
205 const std::string &dstUri,
206 const std::string &srcDeviceId,
207 const sptr<IRemoteObject> &listener)
208 {
209 auto listenerCallback = iface_cast<IFileTransListener>(listener);
210 auto sessionName = SoftBusSessionPool::GetInstance().GenerateSessionName();
211 if (sessionName.empty() || listenerCallback == nullptr) {
212 LOGI("SessionServer exceed max or ListenerCallback is nullptr");
213 return CancelWait(sessionName, listenerCallback);
214 }
215
216 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
217 DistributedHardware::DmDeviceInfo localDeviceInfo{};
218 int errCode = deviceManager.GetLocalDeviceInfo(IDaemon::SERVICE_NAME, localDeviceInfo);
219 if (errCode != E_OK) {
220 LOGI("GetLocalDeviceInfo failed, errCode = %{public}d", errCode);
221 return CancelWait(sessionName, listenerCallback);
222 }
223
224 HapTokenInfo hapTokenInfo;
225 int result = AccessTokenKit::GetHapTokenInfo(IPCSkeleton::GetCallingTokenID(), hapTokenInfo);
226 if (result != Security::AccessToken::AccessTokenKitRet::RET_SUCCESS) {
227 LOGE("GetHapTokenInfo failed, errCode = %{public}d", result);
228 return CancelWait(sessionName, listenerCallback);
229 }
230
231 std::string physicalPath;
232 auto ret = GetRealPath(dstUri, hapTokenInfo, sessionName, physicalPath);
233 if (ret != E_OK) {
234 LOGE("GetRealPath failed, ret = %{public}d", ret);
235 return CancelWait(sessionName, listenerCallback);
236 }
237 SoftBusSessionPool::SessionInfo sessionInfo{.dstPath = physicalPath, .uid = IPCSkeleton::GetCallingUid()};
238 SoftBusSessionPool::GetInstance().AddSessionInfo(sessionName, sessionInfo);
239 ret = SoftBusHandler::GetInstance().CreateSessionServer(IDaemon::SERVICE_NAME, sessionName);
240 if (ret != E_OK) {
241 LOGE("CreateSessionServer failed, ret = %{public}d", ret);
242 RemoveSession(sessionName);
243 return CancelWait(sessionName, listenerCallback);
244 }
245
246 ret = SoftBusHandler::GetInstance().SetFileReceiveListener(IDaemon::SERVICE_NAME, sessionName, physicalPath);
247 if (ret != E_OK) {
248 LOGE("SetFileReceiveListener failed, ret = %{public}d", ret);
249 RemoveSession(sessionName);
250 return CancelWait(sessionName, listenerCallback);
251 }
252 TransManager::GetInstance().AddTransTask(sessionName, listenerCallback);
253 return LoadRemoteSA(srcUri, physicalPath, localDeviceInfo.networkId, srcDeviceId, sessionName);
254 }
255
LoadRemoteSA(const std::string & srcUri,const std::string & dstPath,const std::string & localDeviceId,const std::string & remoteDeviceId,const std::string & sessionName)256 int32_t Daemon::LoadRemoteSA(const std::string &srcUri,
257 const std::string &dstPath,
258 const std::string &localDeviceId,
259 const std::string &remoteDeviceId,
260 const std::string &sessionName)
261 {
262 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
263 if (sam == nullptr) {
264 LOGE("Samgr is nullptr");
265 RemoveSession(sessionName);
266 return E_SA_LOAD_FAILED;
267 }
268
269 auto object = sam->GetSystemAbility(FILEMANAGEMENT_DISTRIBUTED_FILE_DAEMON_SA_ID, remoteDeviceId);
270 if (object == nullptr) {
271 LOGE("GetSystemAbility failed");
272 RemoveSession(sessionName);
273 return E_SA_LOAD_FAILED;
274 }
275 auto daemon = iface_cast<OHOS::Storage::DistributedFile::IDaemon>(object);
276 if (daemon == nullptr) {
277 LOGE("Connect service nullptr");
278 RemoveSession(sessionName);
279 return E_SA_LOAD_FAILED;
280 }
281
282 auto ret = daemon->RequestSendFile(srcUri, dstPath, localDeviceId, sessionName);
283 if (ret != E_OK) {
284 LOGE("RequestSendFile failed, ret = %{public}d", ret);
285 RemoveSession(sessionName);
286 return E_SA_LOAD_FAILED;
287 }
288 return ret;
289 }
290
RemoveSession(const std::string & sessionName)291 void Daemon::RemoveSession(const std::string &sessionName)
292 {
293 TransManager::GetInstance().DeleteTransTask(sessionName);
294 SoftBusSessionPool::GetInstance().DeleteSessionInfo(sessionName);
295 RemoveSessionServer(IDaemon::SERVICE_NAME.c_str(), sessionName.c_str());
296 }
297
GetRealPath(const std::string & dstUri,const HapTokenInfo & hapTokenInfo,const std::string & sessionName,std::string & physicalPath)298 int32_t Daemon::GetRealPath(const std::string &dstUri,
299 const HapTokenInfo &hapTokenInfo,
300 const std::string &sessionName,
301 std::string &physicalPath)
302 {
303 Uri uri(dstUri);
304 auto authority = uri.GetAuthority();
305 if (authority == FILE_MANAGER_AUTHORITY || authority == MEDIA_AUTHORITY) {
306 auto ret = SandboxHelper::GetPhysicalPath(dstUri, std::to_string(hapTokenInfo.userID), physicalPath);
307 if (ret != E_OK) {
308 LOGE("invalid uri, ret = %{public}d", ret);
309 RemoveSession(sessionName);
310 return E_GET_PHYSICAL_PATH_FAILED;
311 }
312 } else {
313 auto bundleName = SoftBusSessionListener::GetBundleName(dstUri);
314 if (bundleName.empty()) {
315 LOGE("not find bundle name");
316 RemoveSession(sessionName);
317 return E_GET_PHYSICAL_PATH_FAILED;
318 }
319 physicalPath = "/data/service/el2/" + to_string(hapTokenInfo.userID) + "/hmdfs/account/data/" + bundleName;
320 }
321 LOGI("physicalPath %{public}s", physicalPath.c_str());
322 if (!SandboxHelper::CheckValidPath(physicalPath)) {
323 LOGE("invalid path.");
324 RemoveSession(sessionName);
325 return E_GET_PHYSICAL_PATH_FAILED;
326 }
327 return E_OK;
328 }
329
CancelWait(const std::string & sessionName,const sptr<IFileTransListener> & listenerCallback)330 int32_t Daemon::CancelWait(const std::string &sessionName, const sptr<IFileTransListener> &listenerCallback)
331 {
332 listenerCallback->OnFailed(sessionName);
333 return E_SOFTBUS_SESSION_FAILED;
334 }
335 } // namespace DistributedFile
336 } // namespace Storage
337 } // namespace OHOS