1 /*
2 * Copyright (c) 2021 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 "softbus_bus_center.h"
29 #include "utils_log.h"
30 #include "parameters.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 LOGE("Device manager agent stop instance failed.");
51 } catch (const std::exception &e) {
52 LOGE("Device manager agent Unexpected Low Level 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 auto smp = mp.lock();
82 if (!smp) {
83 stringstream ss("Failed to join group: Received empty mountpoint");
84 LOGE("%{public}s", ss.str().c_str());
85 throw runtime_error(ss.str());
86 }
87
88 shared_ptr<SoftbusAgent> agent = nullptr;
89 {
90 unique_lock<mutex> lock(mpToNetworksMutex_);
91 agent = make_shared<SoftbusAgent>(mp);
92 auto [ignored, inserted] = mpToNetworks_.insert({ smp->GetID(), agent });
93 if (!inserted) {
94 stringstream ss;
95 ss << "Failed to join group: Mountpoint existed" << smp->ToString();
96 throw runtime_error(ss.str());
97 }
98 }
99 LOGI("smp id %{public}d, is account_less %{pubulic}d", smp->GetID(), agent->GetMountPoint()->isAccountLess());
100 agent->StartActor();
101 }
102
QuitGroup(weak_ptr<MountPoint> mp)103 void DeviceManagerAgent::QuitGroup(weak_ptr<MountPoint> mp)
104 {
105 auto smp = mp.lock();
106 if (!smp) {
107 stringstream ss("Failed to quit group: Received empty mountpoint");
108 LOGE("%{public}s", ss.str().c_str());
109 throw runtime_error(ss.str());
110 }
111
112 unique_lock<mutex> lock(mpToNetworksMutex_);
113 auto it = mpToNetworks_.find(smp->GetID());
114 if (it == mpToNetworks_.end()) {
115 stringstream ss;
116 ss << "Failed to quit group: Mountpoint didn't exist " << smp->ToString();
117 throw runtime_error(ss.str());
118 }
119
120 it->second->StopActor();
121 mpToNetworks_.erase(smp->GetID());
122 }
123
OfflineAllDevice()124 void DeviceManagerAgent::OfflineAllDevice()
125 {
126 unique_lock<mutex> lock(mpToNetworksMutex_);
127 for (auto [ignore, net] : cidNetTypeRecord_) {
128 auto cmd = make_unique<DfsuCmd<NetworkAgentTemplate>>(&NetworkAgentTemplate::DisconnectAllDevices);
129 net->Recv(move(cmd));
130 }
131 }
132
ReconnectOnlineDevices()133 void DeviceManagerAgent::ReconnectOnlineDevices()
134 {
135 unique_lock<mutex> lock(mpToNetworksMutex_);
136 for (auto [ignore, net] : cidNetTypeRecord_) {
137 auto cmd = make_unique<DfsuCmd<NetworkAgentTemplate>>(&NetworkAgentTemplate::ConnectOnlineDevices);
138 cmd->UpdateOption({
139 .tryTimes_ = MAX_RETRY_COUNT,
140 });
141 net->Recv(move(cmd));
142 }
143 }
144
FindNetworkBaseTrustRelation(bool isAccountless)145 std::shared_ptr<NetworkAgentTemplate> DeviceManagerAgent::FindNetworkBaseTrustRelation(bool isAccountless)
146 {
147 LOGI("enter: isAccountless %{public}d", isAccountless);
148 for (auto [ignore, net] : mpToNetworks_) {
149 if (net->GetMountPoint()->isAccountLess() == isAccountless) {
150 return net;
151 }
152 }
153 LOGE("not find this net in mpToNetworks, isAccountless %{public}d", isAccountless);
154 return nullptr;
155 }
156
OnDeviceOnline(const DistributedHardware::DmDeviceInfo & deviceInfo)157 void DeviceManagerAgent::OnDeviceOnline(const DistributedHardware::DmDeviceInfo &deviceInfo)
158 {
159 LOGI("networkId %{public}s, OnDeviceOnline begin", deviceInfo.deviceId);
160
161 // online first query this dev's trust info
162 DeviceInfo info(deviceInfo);
163 QueryRelatedGroups(info.udid_, info.cid_);
164
165 // based on dev's trust info, choose corresponding network agent to obtain socket
166 unique_lock<mutex> lock(mpToNetworksMutex_);
167 auto networkAgent = cidNetTypeRecord_[info.cid_];
168 if (networkAgent == nullptr) {
169 LOGE("cid %{public}s network is null!", info.cid_.c_str());
170 return;
171 }
172 auto cmd =
173 make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>(&NetworkAgentTemplate::ConnectDeviceAsync, info);
174 cmd->UpdateOption({.tryTimes_ = MAX_RETRY_COUNT});
175 networkAgent->Recv(move(cmd));
176
177 LOGI("OnDeviceOnline end");
178 }
179
OnDeviceOffline(const DistributedHardware::DmDeviceInfo & deviceInfo)180 void DeviceManagerAgent::OnDeviceOffline(const DistributedHardware::DmDeviceInfo &deviceInfo)
181 {
182 LOGI("OnDeviceOffline begin");
183 DeviceInfo info(deviceInfo);
184
185 unique_lock<mutex> lock(mpToNetworksMutex_);
186 auto networkAgent = cidNetTypeRecord_[info.cid_];
187 if (networkAgent == nullptr) {
188 LOGE("cid %{public}s network is null!", info.cid_.c_str());
189 return;
190 }
191
192 auto cmd =
193 make_unique<DfsuCmd<NetworkAgentTemplate, const DeviceInfo>>(&NetworkAgentTemplate::DisconnectDevice, info);
194 networkAgent->Recv(move(cmd));
195 cidNetTypeRecord_.erase(info.cid_);
196 LOGI("OnDeviceOffline end");
197 }
198
from_json(const nlohmann::json & jsonObject,GroupInfo & groupInfo)199 void from_json(const nlohmann::json &jsonObject, GroupInfo &groupInfo)
200 {
201 if (jsonObject.find(FIELD_GROUP_NAME) != jsonObject.end()) {
202 groupInfo.groupName = jsonObject.at(FIELD_GROUP_NAME).get<std::string>();
203 }
204
205 if (jsonObject.find(FIELD_GROUP_ID) != jsonObject.end()) {
206 groupInfo.groupId = jsonObject.at(FIELD_GROUP_ID).get<std::string>();
207 }
208
209 if (jsonObject.find(FIELD_GROUP_OWNER) != jsonObject.end()) {
210 groupInfo.groupOwner = jsonObject.at(FIELD_GROUP_OWNER).get<std::string>();
211 }
212
213 if (jsonObject.find(FIELD_GROUP_TYPE) != jsonObject.end()) {
214 groupInfo.groupType = jsonObject.at(FIELD_GROUP_TYPE).get<int32_t>();
215 }
216 }
217
QueryRelatedGroups(const std::string & udid,const std::string & networkId)218 void DeviceManagerAgent::QueryRelatedGroups(const std::string &udid, const std::string &networkId)
219 {
220 int ret = InitDeviceAuthService();
221 if (ret != 0) {
222 LOGE("InitDeviceAuthService failed, ret %{public}d", ret);
223 return;
224 }
225
226 auto hichainDevGroupMgr_ = GetGmInstance();
227 if (hichainDevGroupMgr_ == nullptr) {
228 LOGE("failed to get hichain device group manager");
229 return;
230 }
231
232 char *returnGroupVec = nullptr;
233 uint32_t groupNum = 0;
234 ret = hichainDevGroupMgr_->getRelatedGroups(ANY_OS_ACCOUNT, IDaemon::SERVICE_NAME.c_str(), udid.c_str(),
235 &returnGroupVec, &groupNum);
236 if (ret != 0 || returnGroupVec == nullptr) {
237 LOGE("failed to get related groups, ret %{public}d", ret);
238 return;
239 }
240
241 if (groupNum == 0) {
242 LOGE("failed to get related groups, groupNum is %{public}d", groupNum);
243 return;
244 }
245
246 std::string groups = std::string(returnGroupVec);
247 nlohmann::json jsonObject = nlohmann::json::parse(groups); // transform from cjson to cppjson
248 if (jsonObject.is_discarded()) {
249 LOGE("returnGroupVec parse failed");
250 return;
251 }
252
253 std::vector<GroupInfo> groupList;
254 groupList = jsonObject.get<std::vector<GroupInfo>>();
255 for (auto &a : groupList) {
256 LOGI("group info:[groupName] %{public}s, [groupId] %{public}s, [groupOwner] %{public}s,[groupType] %{public}d,",
257 a.groupName.c_str(), a.groupId.c_str(), a.groupOwner.c_str(), a.groupType);
258 }
259
260 unique_lock<mutex> lock(mpToNetworksMutex_);
261 for (const auto &group : groupList) {
262 if (CheckIsAccountless(group)) {
263 cidNetTypeRecord_.insert({ networkId, FindNetworkBaseTrustRelation(true) });
264 } else {
265 cidNetTypeRecord_.insert({ networkId, FindNetworkBaseTrustRelation(false) });
266 }
267 }
268
269 return;
270 }
271
CheckIsAccountless(const GroupInfo & group)272 bool DeviceManagerAgent::CheckIsAccountless(const GroupInfo &group)
273 {
274 // because of there no same_account, only for test, del later
275 LOGI("SAME_ACCOUNT_MARK val is %{public}d", system::GetBoolParameter(SAME_ACCOUNT_MARK, false));
276 if (system::GetBoolParameter(SAME_ACCOUNT_MARK, false) == true) { // isaccountless == false
277 LOGI("SAME_ACCOUNT_MARK val is true(same account)");
278 return false;
279 } else { // isaccountless == true
280 return true;
281 }
282
283 if (group.groupType == PEER_TO_PEER_GROUP || group.groupType == ACROSS_ACCOUNT_AUTHORIZE_GROUP) {
284 return true;
285 }
286 return false;
287 }
288
OnDeviceChanged(const DistributedHardware::DmDeviceInfo & deviceInfo)289 void DeviceManagerAgent::OnDeviceChanged(const DistributedHardware::DmDeviceInfo &deviceInfo)
290 {
291 LOGI("OnDeviceInfoChanged");
292 }
293
InitLocalNodeInfo()294 void DeviceManagerAgent::InitLocalNodeInfo()
295 {
296 NodeBasicInfo tmpNodeInfo;
297 int errCode = GetLocalNodeDeviceInfo(IDaemon::SERVICE_NAME.c_str(), &tmpNodeInfo);
298 if (errCode != 0) {
299 ThrowException(errCode, "Failed to get info of local devices");
300 }
301 localDeviceInfo_.SetCid(string(tmpNodeInfo.networkId));
302 }
303
OnRemoteDied()304 void DeviceManagerAgent::OnRemoteDied()
305 {
306 LOGI("device manager service died");
307 StopInstance();
308 OfflineAllDevice(); // cannot commit a cmd to queue
309 StartInstance();
310 ReconnectOnlineDevices();
311 }
GetLocalDeviceInfo()312 DeviceInfo &DeviceManagerAgent::GetLocalDeviceInfo()
313 {
314 return localDeviceInfo_;
315 }
316
GetRemoteDevicesInfo()317 vector<DeviceInfo> DeviceManagerAgent::GetRemoteDevicesInfo()
318 {
319 string extra = "";
320 string pkgName = IDaemon::SERVICE_NAME;
321 vector<DistributedHardware::DmDeviceInfo> deviceList;
322
323 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
324 int errCode = deviceManager.GetTrustedDeviceList(pkgName, extra, deviceList);
325 if (errCode) {
326 ThrowException(errCode, "Failed to get info of remote devices");
327 }
328
329 vector<DeviceInfo> res;
330 for (const auto &item : deviceList) {
331 res.push_back(DeviceInfo(item));
332 }
333 return res;
334 }
335
RegisterToExternalDm()336 void DeviceManagerAgent::RegisterToExternalDm()
337 {
338 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
339 string pkgName = IDaemon::SERVICE_NAME;
340 int errCode = deviceManager.InitDeviceManager(pkgName, shared_from_this());
341 if (errCode != 0) {
342 ThrowException(errCode, "Failed to InitDeviceManager");
343 }
344 string extra = "";
345 errCode = deviceManager.RegisterDevStateCallback(pkgName, extra, shared_from_this());
346 if (errCode != 0) {
347 ThrowException(errCode, "Failed to RegisterDevStateCallback");
348 }
349 LOGI("RegisterToExternalDm Succeed");
350 }
351
UnregisterFromExternalDm()352 void DeviceManagerAgent::UnregisterFromExternalDm()
353 {
354 auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
355 string pkgName = IDaemon::SERVICE_NAME;
356 int errCode = deviceManager.UnRegisterDevStateCallback(pkgName);
357 if (errCode != 0) {
358 ThrowException(errCode, "Failed to UnRegisterDevStateCallback");
359 }
360 errCode = deviceManager.UnInitDeviceManager(pkgName);
361 if (errCode != 0) {
362 ThrowException(errCode, "Failed to UnInitDeviceManager");
363 }
364 LOGI("UnregisterFromExternalDm Succeed");
365 }
366 } // namespace DistributedFile
367 } // namespace Storage
368 } // namespace OHOS
369