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