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