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 "device/device_manager_agent.h"
17
18 #include <limits>
19 #include <sstream>
20 #include <string>
21
22 #include "device_auth.h"
23 #include "dfsu_exception.h"
24 #include "ipc/i_daemon.h"
25 #include "mountpoint/mount_manager.h"
26 #include "network/devsl_dispatcher.h"
27 #include "network/softbus/softbus_agent.h"
28 #include "parameters.h"
29 #include "softbus_bus_center.h"
30 #include "utils_log.h"
31
32 namespace OHOS {
33 namespace Storage {
34 namespace DistributedFile {
35 namespace {
36 constexpr int MAX_RETRY_COUNT = 7;
37 constexpr int PEER_TO_PEER_GROUP = 256;
38 constexpr int ACROSS_ACCOUNT_AUTHORIZE_GROUP = 1282;
39 const std::string SAME_ACCOUNT_MARK = "const.distributed_file_only_for_same_account_test";
40 } // namespace
41 using namespace std;
42
DeviceManagerAgent()43 DeviceManagerAgent::DeviceManagerAgent() : DfsuActor<DeviceManagerAgent>(this, std::numeric_limits<uint32_t>::max()) {}
44
~DeviceManagerAgent()45 DeviceManagerAgent::~DeviceManagerAgent()
46 {
47 try {
48 StopInstance();
49 } catch (const DfsuException &e) {
50 // do not throw exception
51 } catch (const std::exception &e) {
52 // do not throw exception
53 }
54 }
55
StartInstance()56 void DeviceManagerAgent::StartInstance()
57 {
58 StartActor();
59 }
60
StopInstance()61 void DeviceManagerAgent::StopInstance()
62 {
63 StopActor();
64 }
65
Start()66 void DeviceManagerAgent::Start()
67 {
68 DevslDispatcher::Start();
69 RegisterToExternalDm();
70 InitLocalNodeInfo();
71 }
72
Stop()73 void DeviceManagerAgent::Stop()
74 {
75 UnregisterFromExternalDm();
76 DevslDispatcher::Stop();
77 }
78
JoinGroup(weak_ptr<MountPoint> mp)79 void DeviceManagerAgent::JoinGroup(weak_ptr<MountPoint> mp)
80 {
81 LOGI("join group begin");
82 auto smp = mp.lock();
83 if (!smp) {
84 stringstream ss("Failed to join group: Received empty mountpoint");
85 LOGE("%{public}s", ss.str().c_str());
86 throw runtime_error(ss.str());
87 }
88
89 shared_ptr<SoftbusAgent> agent = nullptr;
90 {
91 unique_lock<mutex> lock(mpToNetworksMutex_);
92 agent = make_shared<SoftbusAgent>(mp);
93 auto [ignored, inserted] = mpToNetworks_.insert({ smp->GetID(), agent });
94 if (!inserted) {
95 stringstream ss;
96 ss << "Failed to join group: Mountpoint existed" << smp->ToString();
97 throw runtime_error(ss.str());
98 }
99 }
100 agent->StartActor();
101 LOGI("join group end, id : %{public}d, account : %{public}s", smp->GetID(), smp->isAccountLess() ? "no" : "yes");
102 }
103
QuitGroup(weak_ptr<MountPoint> mp)104 void DeviceManagerAgent::QuitGroup(weak_ptr<MountPoint> mp)
105 {
106 LOGI("quit group begin");
107 OfflineAllDevice();
108
109 auto smp = mp.lock();
110 if (!smp) {
111 stringstream ss("Failed to quit group: Received empty mountpoint");
112 LOGE("%{public}s", ss.str().c_str());
113 throw runtime_error(ss.str());
114 }
115
116 unique_lock<mutex> lock(mpToNetworksMutex_);
117 auto it = mpToNetworks_.find(smp->GetID());
118 if (it == mpToNetworks_.end()) {
119 stringstream ss;
120 ss << "Failed to quit group: Mountpoint didn't exist " << smp->ToString();
121 throw runtime_error(ss.str());
122 }
123
124 it->second->StopActor();
125 mpToNetworks_.erase(smp->GetID());
126 LOGI("quit group end, id : %{public}d, account : %{public}s", smp->GetID(), smp->isAccountLess() ? "no" : "yes");
127 }
128
OfflineAllDevice()129 void DeviceManagerAgent::OfflineAllDevice()
130 {
131 unique_lock<mutex> lock(mpToNetworksMutex_);
132 for (auto [ignore, net] : cidNetTypeRecord_) {
133 if (net == nullptr) {
134 continue;
135 }
136 auto cmd = make_unique<DfsuCmd<NetworkAgentTemplate>>(&NetworkAgentTemplate::DisconnectAllDevices);
137 net->Recv(move(cmd));
138 }
139 }
140
ReconnectOnlineDevices()141 void DeviceManagerAgent::ReconnectOnlineDevices()
142 {
143 unique_lock<mutex> lock(mpToNetworksMutex_);
144 for (auto [ignore, net] : cidNetTypeRecord_) {
145 if (net == nullptr) {
146 continue;
147 }
148 auto cmd = make_unique<DfsuCmd<NetworkAgentTemplate>>(&NetworkAgentTemplate::ConnectOnlineDevices);
149 cmd->UpdateOption({
150 .tryTimes_ = MAX_RETRY_COUNT,
151 });
152 net->Recv(move(cmd));
153 }
154 }
155
FindNetworkBaseTrustRelation(bool isAccountless)156 std::shared_ptr<NetworkAgentTemplate> DeviceManagerAgent::FindNetworkBaseTrustRelation(bool isAccountless)
157 {
158 LOGI("enter: isAccountless %{public}d", isAccountless);
159 for (auto [ignore, net] : mpToNetworks_) {
160 if (net != nullptr) {
161 auto smp = net->GetMountPoint();
162 if (smp != nullptr && smp->isAccountLess() == isAccountless) {
163 return net;
164 }
165 }
166 }
167 LOGE("not find this net in mpToNetworks, isAccountless %{public}d", isAccountless);
168 return nullptr;
169 }
170
GetNetworkType(const string & cid)171 int32_t DeviceManagerAgent::GetNetworkType(const string &cid)
172 {
173 int32_t networkType = 0;
174 string pkgName = IDaemon::SERVICE_NAME;
175 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
176 int errCode = deviceManager.GetNetworkTypeByNetworkId(pkgName, cid, networkType);
177 if (errCode) {
178 LOGE("get network type error:%{public}d", errCode);
179 }
180
181 return networkType;
182 }
183
IsWifiNetworkType(int32_t networkType)184 bool DeviceManagerAgent::IsWifiNetworkType(int32_t networkType)
185 {
186 if ((networkType == -1) || !(networkType & (1 << DistributedHardware::BIT_NETWORK_TYPE_WIFI))) {
187 return false;
188 }
189
190 return true;
191 }
192
OnDeviceOnline(const DistributedHardware::DmDeviceInfo & deviceInfo)193 void DeviceManagerAgent::OnDeviceOnline(const DistributedHardware::DmDeviceInfo &deviceInfo)
194 {
195 LOGI("networkId %{public}s, OnDeviceOnline begin", deviceInfo.deviceId);
196
197 // online first query this dev's trust info
198 DeviceInfo info(deviceInfo);
199 QueryRelatedGroups(info.udid_, info.cid_);
200
201 // based on dev's trust info, choose corresponding network agent to obtain socket
202 unique_lock<mutex> lock(mpToNetworksMutex_);
203
204 auto it = cidNetTypeRecord_.find(info.cid_);
205 if (it == cidNetTypeRecord_.end()) {
206 LOGE("cid %{public}s network is null!", info.cid_.c_str());
207 LOGI("OnDeviceOnline end");
208 return;
209 }
210
211 auto type_ = cidNetworkType_.find(info.cid_);
212 if (type_ == cidNetworkType_.end()) {
213 LOGE("cid %{public}s network type is null!", info.cid_.c_str());
214 LOGI("OnDeviceOnline end");
215 return;
216 }
217
218 int32_t newNetworkType = type_->second = GetNetworkType(info.cid_);
219 LOGI("newNetworkType:%{public}d", newNetworkType);
220
221 if (!IsWifiNetworkType(newNetworkType)) {
222 LOGE("cid %{public}s networkType:%{public}d", info.cid_.c_str(), type_->second);
223 LOGI("OnDeviceOnline end");
224 return;
225 }
226
227 auto cmd =
228 make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>(&NetworkAgentTemplate::ConnectDeviceAsync, info);
229 cmd->UpdateOption({.tryTimes_ = MAX_RETRY_COUNT});
230 it->second->Recv(move(cmd));
231
232 LOGI("OnDeviceOnline end");
233 }
234
OnDeviceOffline(const DistributedHardware::DmDeviceInfo & deviceInfo)235 void DeviceManagerAgent::OnDeviceOffline(const DistributedHardware::DmDeviceInfo &deviceInfo)
236 {
237 LOGI("OnDeviceOffline begin");
238 DeviceInfo info(deviceInfo);
239
240 unique_lock<mutex> lock(mpToNetworksMutex_);
241 auto it = cidNetTypeRecord_.find(info.cid_);
242 if (it == cidNetTypeRecord_.end()) {
243 LOGE("cid %{public}s network is null!", info.cid_.c_str());
244 LOGI("OnDeviceOffline end");
245 return;
246 }
247
248 auto type_ = cidNetworkType_.find(info.cid_);
249 if (type_ == cidNetworkType_.end()) {
250 LOGE("cid %{public}s network type is null!", info.cid_.c_str());
251 LOGI("OnDeviceOffline end");
252 return;
253 }
254
255 auto cmd =
256 make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>(&NetworkAgentTemplate::DisconnectDevice, info);
257 it->second->Recv(move(cmd));
258 cidNetTypeRecord_.erase(info.cid_);
259 cidNetworkType_.erase(info.cid_);
260 LOGI("OnDeviceOffline end");
261 }
262
OnDeviceP2POnline(const DistributedHardware::DmDeviceInfo & deviceInfo)263 int32_t DeviceManagerAgent::OnDeviceP2POnline(const DistributedHardware::DmDeviceInfo &deviceInfo)
264 {
265 LOGI("[OnDeviceP2POnline] networkId %{public}s, OnDeviceOnline begin", deviceInfo.networkId);
266 DeviceInfo info(deviceInfo);
267 LOGI("[OnDeviceP2POnline] networkId %{public}s, QueryRelatedGroups begin", deviceInfo.networkId);
268 QueryRelatedGroups(info.udid_, info.cid_);
269 LOGI("[OnDeviceP2POnline] networkId %{public}s, QueryRelatedGroups end", deviceInfo.networkId);
270 unique_lock<mutex> lock(mpToNetworksMutex_);
271 auto it = cidNetTypeRecord_.find(info.cid_);
272 if (it == cidNetTypeRecord_.end()) {
273 LOGE("[OnDeviceP2POnline] cid %{public}s network is null!", info.cid_.c_str());
274 return P2P_FAILED;
275 }
276 auto type_ = cidNetworkType_.find(info.cid_);
277 if (type_ == cidNetworkType_.end()) {
278 LOGE("[OnDeviceP2POnline] cid %{public}s network type is null!", info.cid_.c_str());
279 return P2P_FAILED;
280 }
281 openP2PSessionCount_++;
282 auto cmd = make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>(
283 &NetworkAgentTemplate::ConnectDeviceByP2PAsync, info);
284 cmd->UpdateOption({.tryTimes_ = MAX_RETRY_COUNT});
285 it->second->Recv(move(cmd));
286 LOGI("[OnDeviceP2POnline] networkId %{public}s, OnDeviceOnline end", deviceInfo.networkId);
287 return P2P_SUCCESS;
288 }
289
OnDeviceP2POffline(const DistributedHardware::DmDeviceInfo & deviceInfo)290 int32_t DeviceManagerAgent::OnDeviceP2POffline(const DistributedHardware::DmDeviceInfo &deviceInfo)
291 {
292 LOGI("OnDeviceP2POffline begin");
293 DeviceInfo info(deviceInfo);
294
295 unique_lock<mutex> lock(mpToNetworksMutex_);
296 openP2PSessionCount_--;
297 if (openP2PSessionCount_) {
298 return P2P_FAILED;
299 }
300 auto it = cidNetTypeRecord_.find(info.cid_);
301 if (it == cidNetTypeRecord_.end()) {
302 LOGE("cid %{public}s network is null!", info.cid_.c_str());
303 return P2P_FAILED;
304 }
305 auto type_ = cidNetworkType_.find(info.cid_);
306 if (type_ == cidNetworkType_.end()) {
307 LOGE("cid %{public}s network type is null!", info.cid_.c_str());
308 return P2P_FAILED;
309 }
310 auto cmd =
311 make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>(&NetworkAgentTemplate::DisconnectDevice, info);
312 it->second->Recv(move(cmd));
313 cidNetTypeRecord_.erase(info.cid_);
314 cidNetworkType_.erase(info.cid_);
315 LOGI("OnDeviceP2POffline end");
316 return P2P_SUCCESS;
317 }
318
from_json(const nlohmann::json & jsonObject,GroupInfo & groupInfo)319 void from_json(const nlohmann::json &jsonObject, GroupInfo &groupInfo)
320 {
321 if (jsonObject.find(FIELD_GROUP_NAME) != jsonObject.end()) {
322 groupInfo.groupName = jsonObject.at(FIELD_GROUP_NAME).get<std::string>();
323 }
324
325 if (jsonObject.find(FIELD_GROUP_ID) != jsonObject.end()) {
326 groupInfo.groupId = jsonObject.at(FIELD_GROUP_ID).get<std::string>();
327 }
328
329 if (jsonObject.find(FIELD_GROUP_OWNER) != jsonObject.end()) {
330 groupInfo.groupOwner = jsonObject.at(FIELD_GROUP_OWNER).get<std::string>();
331 }
332
333 if (jsonObject.find(FIELD_GROUP_TYPE) != jsonObject.end()) {
334 groupInfo.groupType = jsonObject.at(FIELD_GROUP_TYPE).get<int32_t>();
335 }
336 }
337
QueryRelatedGroups(const std::string & udid,const std::string & networkId)338 void DeviceManagerAgent::QueryRelatedGroups(const std::string &udid, const std::string &networkId)
339 {
340 int ret = InitDeviceAuthService();
341 if (ret != 0) {
342 LOGE("InitDeviceAuthService failed, ret %{public}d", ret);
343 return;
344 }
345
346 auto hichainDevGroupMgr_ = GetGmInstance();
347 if (hichainDevGroupMgr_ == nullptr) {
348 LOGE("failed to get hichain device group manager");
349 return;
350 }
351
352 char *returnGroupVec = nullptr;
353 uint32_t groupNum = 0;
354 ret = hichainDevGroupMgr_->getRelatedGroups(ANY_OS_ACCOUNT, IDaemon::SERVICE_NAME.c_str(), udid.c_str(),
355 &returnGroupVec, &groupNum);
356 if (ret != 0 || returnGroupVec == nullptr) {
357 LOGE("failed to get related groups, ret %{public}d", ret);
358 return;
359 }
360
361 if (groupNum == 0) {
362 LOGE("failed to get related groups, groupNum is %{public}u", groupNum);
363 return;
364 }
365
366 std::string groups = std::string(returnGroupVec);
367 nlohmann::json jsonObject = nlohmann::json::parse(groups); // transform from cjson to cppjson
368 if (jsonObject.is_discarded()) {
369 LOGE("returnGroupVec parse failed");
370 return;
371 }
372
373 std::vector<GroupInfo> groupList;
374 groupList = jsonObject.get<std::vector<GroupInfo>>();
375 for (auto &a : groupList) {
376 LOGI("group info:[groupName] %{public}s, [groupId] %{public}s, [groupOwner] %{public}s,[groupType] %{public}d,",
377 a.groupName.c_str(), a.groupId.c_str(), a.groupOwner.c_str(), a.groupType);
378 }
379
380 unique_lock<mutex> lock(mpToNetworksMutex_);
381 for (const auto &group : groupList) {
382 auto network = FindNetworkBaseTrustRelation(CheckIsAccountless(group));
383 if (network != nullptr) {
384 cidNetTypeRecord_.insert({ networkId, network });
385 cidNetworkType_.insert({ networkId, GetNetworkType(networkId) });
386 }
387 }
388
389 return;
390 }
391
CheckIsAccountless(const GroupInfo & group)392 bool DeviceManagerAgent::CheckIsAccountless(const GroupInfo &group)
393 {
394 // because of there no same_account, only for test, del later
395 LOGI("SAME_ACCOUNT_MARK val is %{public}d", system::GetBoolParameter(SAME_ACCOUNT_MARK, false));
396 if (system::GetBoolParameter(SAME_ACCOUNT_MARK, false) == true) { // isaccountless == false
397 LOGI("SAME_ACCOUNT_MARK val is true(same account)");
398 return false;
399 } else { // isaccountless == true
400 return true;
401 }
402
403 if (group.groupType == PEER_TO_PEER_GROUP || group.groupType == ACROSS_ACCOUNT_AUTHORIZE_GROUP) {
404 return true;
405 }
406 return false;
407 }
408
OnDeviceChanged(const DistributedHardware::DmDeviceInfo & deviceInfo)409 void DeviceManagerAgent::OnDeviceChanged(const DistributedHardware::DmDeviceInfo &deviceInfo)
410 {
411 LOGI("OnDeviceInfoChanged begin");
412 DeviceInfo info(deviceInfo);
413 unique_lock<mutex> lock(mpToNetworksMutex_);
414
415 auto it = cidNetTypeRecord_.find(info.cid_);
416 if (it == cidNetTypeRecord_.end()) {
417 LOGE("cid %{public}s network is null!", info.cid_.c_str());
418 LOGI("OnDeviceInfoChanged end");
419 return;
420 }
421
422 auto type_ = cidNetworkType_.find(info.cid_);
423 if (type_ == cidNetworkType_.end()) {
424 LOGE("cid %{public}s network type is null!", info.cid_.c_str());
425 LOGI("OnDeviceInfoChanged end");
426 return;
427 }
428
429 int32_t oldNetworkType = type_->second;
430 int32_t newNetworkType = type_->second = deviceInfo.networkType;
431
432 LOGI("oldNetworkType %{public}d, newNetworkType %{public}d", oldNetworkType, newNetworkType);
433
434 if (IsWifiNetworkType(newNetworkType) && !IsWifiNetworkType(oldNetworkType)) {
435 LOGI("Wifi connect");
436 auto cmd = make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>(
437 &NetworkAgentTemplate::ConnectDeviceAsync, info);
438 cmd->UpdateOption({.tryTimes_ = MAX_RETRY_COUNT});
439 it->second->Recv(move(cmd));
440 LOGI("OnDeviceInfoChanged end");
441 return;
442 }
443
444 if (!IsWifiNetworkType(newNetworkType) && IsWifiNetworkType(oldNetworkType)) {
445 LOGI("Wifi disconnect");
446 auto cmd = make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>
447 (&NetworkAgentTemplate::DisconnectDevice, info);
448 it->second->Recv(move(cmd));
449 LOGI("OnDeviceInfoChanged end");
450 return;
451 }
452
453 LOGI("OnDeviceInfoChanged end");
454 }
455
InitDeviceInfos()456 void DeviceManagerAgent::InitDeviceInfos()
457 {
458 string extra = "";
459 string pkgName = IDaemon::SERVICE_NAME;
460 vector<DistributedHardware::DmDeviceInfo> deviceInfoList;
461
462 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
463 int errCode = deviceManager.GetTrustedDeviceList(pkgName, extra, deviceInfoList);
464 if (errCode) {
465 THROW_EXCEPTION(errCode, "Failed to get info of remote devices");
466 }
467
468 for (const auto &deviceInfo : deviceInfoList) {
469 DeviceInfo info(deviceInfo);
470 QueryRelatedGroups(info.udid_, info.cid_);
471 }
472 }
473
InitLocalNodeInfo()474 void DeviceManagerAgent::InitLocalNodeInfo()
475 {
476 NodeBasicInfo tmpNodeInfo;
477 int errCode = GetLocalNodeDeviceInfo(IDaemon::SERVICE_NAME.c_str(), &tmpNodeInfo);
478 if (errCode != 0) {
479 THROW_EXCEPTION(errCode, "Failed to get info of local devices");
480 }
481 localDeviceInfo_.SetCid(string(tmpNodeInfo.networkId));
482 }
483
OnRemoteDied()484 void DeviceManagerAgent::OnRemoteDied()
485 {
486 LOGI("device manager service died");
487 }
488
GetLocalDeviceInfo()489 DeviceInfo &DeviceManagerAgent::GetLocalDeviceInfo()
490 {
491 return localDeviceInfo_;
492 }
493
GetRemoteDevicesInfo()494 vector<DeviceInfo> DeviceManagerAgent::GetRemoteDevicesInfo()
495 {
496 string extra = "";
497 string pkgName = IDaemon::SERVICE_NAME;
498 vector<DistributedHardware::DmDeviceInfo> deviceList;
499
500 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
501 int errCode = deviceManager.GetTrustedDeviceList(pkgName, extra, deviceList);
502 if (errCode) {
503 THROW_EXCEPTION(errCode, "Failed to get info of remote devices");
504 }
505
506 vector<DeviceInfo> res;
507 for (const auto &item : deviceList) {
508 res.push_back(DeviceInfo(item));
509 }
510 return res;
511 }
512
RegisterToExternalDm()513 void DeviceManagerAgent::RegisterToExternalDm()
514 {
515 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
516 string pkgName = IDaemon::SERVICE_NAME;
517 int errCode = deviceManager.InitDeviceManager(pkgName, shared_from_this());
518 if (errCode != 0) {
519 THROW_EXCEPTION(errCode, "Failed to InitDeviceManager");
520 }
521 string extra = "";
522 errCode = deviceManager.RegisterDevStateCallback(pkgName, extra, shared_from_this());
523 if (errCode != 0) {
524 THROW_EXCEPTION(errCode, "Failed to RegisterDevStateCallback");
525 }
526 LOGI("RegisterToExternalDm Succeed");
527 }
528
UnregisterFromExternalDm()529 void DeviceManagerAgent::UnregisterFromExternalDm()
530 {
531 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
532 string pkgName = IDaemon::SERVICE_NAME;
533 int errCode = deviceManager.UnRegisterDevStateCallback(pkgName);
534 if (errCode != 0) {
535 THROW_EXCEPTION(errCode, "Failed to UnRegisterDevStateCallback");
536 }
537 errCode = deviceManager.UnInitDeviceManager(pkgName);
538 if (errCode != 0) {
539 THROW_EXCEPTION(errCode, "Failed to UnInitDeviceManager");
540 }
541 LOGI("UnregisterFromExternalDm Succeed");
542 }
543 } // namespace DistributedFile
544 } // namespace Storage
545 } // namespace OHOS
546