1 /*
2 * Copyright (c) 2022 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 #include "soft_bus_manager.h"
16
17 #include <securec.h>
18
19 #include "device_info_manager.h"
20 #include "parameter.h"
21
22 namespace OHOS {
23 namespace Security {
24 namespace AccessToken {
25 namespace {
26 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "SoftBusManager"};
27 }
28 namespace {
29 static const std::string SESSION_GROUP_ID = "atm_dsoftbus_session_group_id";
30 static const SessionAttribute SESSION_ATTR = {.dataType = TYPE_BYTES};
31
32 static const int REASON_EXIST = -3;
33 static const int OPENSESSION_RETRY_TIMES = 10 * 3;
34 static const int OPENSESSION_RETRY_INTERVAL_MS = 100;
35 static const int UDID_MAX_LENGTH = 128; // udid/uuid max length
36 } // namespace
37
38 const std::string SoftBusManager::ACCESS_TOKEN_PACKAGE_NAME = "ohos.security.distributed_access_token";
39 const std::string SoftBusManager::SESSION_NAME = "ohos.security.atm_channel";
40
SoftBusManager()41 SoftBusManager::SoftBusManager() : isSoftBusServiceBindSuccess_(false), inited_(false), mutex_(), fulfillMutex_()
42 {
43 ACCESSTOKEN_LOG_DEBUG(LABEL, "SoftBusManager()");
44 }
45
~SoftBusManager()46 SoftBusManager::~SoftBusManager()
47 {
48 ACCESSTOKEN_LOG_DEBUG(LABEL, "~SoftBusManager()");
49 }
50
GetInstance()51 SoftBusManager &SoftBusManager::GetInstance()
52 {
53 static SoftBusManager instance;
54 return instance;
55 }
56
Initialize()57 void SoftBusManager::Initialize()
58 {
59 bool inited = false;
60 // cas failed means already inited.
61 if (!inited_.compare_exchange_strong(inited, true)) {
62 ACCESSTOKEN_LOG_DEBUG(LABEL, "already initialized, skip");
63 return;
64 }
65
66 std::function<void()> runner = [&]() {
67 auto sleepTime = std::chrono::milliseconds(1000);
68 while (1) {
69 std::unique_lock<std::mutex> lock(mutex_);
70 std::string packageName = ACCESS_TOKEN_PACKAGE_NAME;
71 std::shared_ptr<MyDmInitCallback> ptrDmInitCallback = std::make_shared<MyDmInitCallback>();
72 int ret =
73 DistributedHardware::DeviceManager::GetInstance().InitDeviceManager(packageName, ptrDmInitCallback);
74 if (ret != ERR_OK) {
75 ACCESSTOKEN_LOG_ERROR(LABEL, "Initialize: InitDeviceManager error, result: %{public}d", ret);
76 std::this_thread::sleep_for(sleepTime);
77 continue;
78 }
79
80 std::string extra = "";
81 std::shared_ptr<SoftBusDeviceConnectionListener> ptrDeviceStateCallback =
82 std::make_shared<SoftBusDeviceConnectionListener>();
83 ret = DistributedHardware::DeviceManager::GetInstance().RegisterDevStateCallback(packageName, extra,
84 ptrDeviceStateCallback);
85 if (ret != ERR_OK) {
86 ACCESSTOKEN_LOG_ERROR(LABEL, "Initialize: RegisterDevStateCallback error, result: %{public}d", ret);
87 std::this_thread::sleep_for(sleepTime);
88 continue;
89 }
90
91 // register session listener
92 ISessionListener sessionListener;
93 sessionListener.OnSessionOpened = SoftBusSessionListener::OnSessionOpened;
94 sessionListener.OnSessionClosed = SoftBusSessionListener::OnSessionClosed;
95 sessionListener.OnBytesReceived = SoftBusSessionListener::OnBytesReceived;
96 sessionListener.OnMessageReceived = SoftBusSessionListener::OnMessageReceived;
97
98 ret = ::CreateSessionServer(ACCESS_TOKEN_PACKAGE_NAME.c_str(), SESSION_NAME.c_str(), &sessionListener);
99 ACCESSTOKEN_LOG_INFO(LABEL, "Initialize: createSessionServer, result: %{public}d", ret);
100 // REASON_EXIST
101 if ((ret != Constant::SUCCESS) && (ret != REASON_EXIST)) {
102 ACCESSTOKEN_LOG_ERROR(LABEL, "Initialize: CreateSessionServer error, result: %{public}d", ret);
103 std::this_thread::sleep_for(sleepTime);
104 continue;
105 }
106
107 isSoftBusServiceBindSuccess_ = true;
108 this->FulfillLocalDeviceInfo();
109 return;
110 }
111 };
112
113 std::thread initThread(runner);
114 initThread.detach();
115 ACCESSTOKEN_LOG_DEBUG(LABEL, "Initialize thread started");
116 }
117
Destroy()118 void SoftBusManager::Destroy()
119 {
120 ACCESSTOKEN_LOG_DEBUG(LABEL, "destroy, init: %{public}d, isSoftBusServiceBindSuccess: %{public}d", inited_.load(),
121 isSoftBusServiceBindSuccess_);
122
123 if (inited_.load() == false) {
124 ACCESSTOKEN_LOG_DEBUG(LABEL, "not inited, skip");
125 return;
126 }
127
128 std::unique_lock<std::mutex> lock(mutex_);
129 if (inited_.load() == false) {
130 ACCESSTOKEN_LOG_DEBUG(LABEL, "not inited, skip");
131 return;
132 }
133
134 if (isSoftBusServiceBindSuccess_) {
135 int32_t ret = ::RemoveSessionServer(ACCESS_TOKEN_PACKAGE_NAME.c_str(), SESSION_NAME.c_str());
136 ACCESSTOKEN_LOG_DEBUG(LABEL, "destroy, RemoveSessionServer: %{public}d", ret);
137 isSoftBusServiceBindSuccess_ = false;
138 }
139
140 std::string packageName = ACCESS_TOKEN_PACKAGE_NAME;
141 int ret = DistributedHardware::DeviceManager::GetInstance().UnRegisterDevStateCallback(packageName);
142 if (ret != ERR_OK) {
143 ACCESSTOKEN_LOG_ERROR(LABEL, "UnRegisterDevStateCallback failed, code: %{public}d", ret);
144 }
145 ret = DistributedHardware::DeviceManager::GetInstance().UnInitDeviceManager(packageName);
146 if (ret != ERR_OK) {
147 ACCESSTOKEN_LOG_ERROR(LABEL, "UnInitDeviceManager failed, code: %{public}d", ret);
148 }
149
150 inited_.store(false);
151
152 ACCESSTOKEN_LOG_DEBUG(LABEL, "destroy, done");
153 }
154
OpenSession(const std::string & deviceId)155 int32_t SoftBusManager::OpenSession(const std::string &deviceId)
156 {
157 #ifdef DEBUG_API_PERFORMANCE
158 ACCESSTOKEN_LOG_INFO(LABEL, "api_performance:start open session");
159 #endif
160
161 DeviceInfo info;
162 bool result = DeviceInfoManager::GetInstance().GetDeviceInfo(deviceId, DeviceIdType::UNKNOWN, info);
163 if (result == false) {
164 ACCESSTOKEN_LOG_WARN(LABEL, "device info notfound for deviceId");
165 return Constant::FAILURE;
166 }
167 std::string networkId = info.deviceId.networkId;
168 ACCESSTOKEN_LOG_INFO(LABEL, "openSession, networkId");
169
170 // async open session, should waitting for OnSessionOpened event.
171 int sessionId = ::OpenSession(SESSION_NAME.c_str(), SESSION_NAME.c_str(), networkId.c_str(),
172 SESSION_GROUP_ID.c_str(), &SESSION_ATTR);
173
174 ACCESSTOKEN_LOG_DEBUG(LABEL, "async open session");
175
176 // wait session opening
177 int retryTimes = 0;
178 int logSpan = 10;
179 auto sleepTime = std::chrono::milliseconds(OPENSESSION_RETRY_INTERVAL_MS);
180 while (retryTimes++ < OPENSESSION_RETRY_TIMES) {
181 if (SoftBusSessionListener::GetSessionState(sessionId) < 0) {
182 std::this_thread::sleep_for(sleepTime);
183 if (retryTimes % logSpan == 0) {
184 ACCESSTOKEN_LOG_INFO(LABEL, "openSession, waitting for: %{public}d ms",
185 retryTimes * OPENSESSION_RETRY_INTERVAL_MS);
186 }
187 continue;
188 }
189 break;
190 }
191 #ifdef DEBUG_API_PERFORMANCE
192 ACCESSTOKEN_LOG_INFO(LABEL, "api_performance:start open session success");
193 #endif
194 int64_t state = SoftBusSessionListener::GetSessionState(sessionId);
195 if (state < 0) {
196 ACCESSTOKEN_LOG_ERROR(LABEL, "openSession, timeout, session: %{public}" PRId64, state);
197 return Constant::FAILURE;
198 }
199
200 SoftBusSessionListener::DeleteSessionIdFromMap(sessionId);
201
202 ACCESSTOKEN_LOG_DEBUG(LABEL, "openSession, succeed, session: %{public}" PRId64, state);
203 return sessionId;
204 }
205
CloseSession(int sessionId)206 int SoftBusManager::CloseSession(int sessionId)
207 {
208 if (sessionId < 0) {
209 ACCESSTOKEN_LOG_INFO(LABEL, "closeSession: session is invalid");
210 return Constant::FAILURE;
211 }
212
213 ::CloseSession(sessionId);
214 ACCESSTOKEN_LOG_INFO(LABEL, "closeSession ");
215 return Constant::SUCCESS;
216 }
217
GetUniversallyUniqueIdByNodeId(const std::string & nodeId)218 std::string SoftBusManager::GetUniversallyUniqueIdByNodeId(const std::string &nodeId)
219 {
220 if (!DataValidator::IsDeviceIdValid(nodeId)) {
221 ACCESSTOKEN_LOG_ERROR(LABEL, "invalid nodeId");
222 return "";
223 }
224
225 std::string uuid = GetUuidByNodeId(nodeId);
226 if (uuid.empty()) {
227 ACCESSTOKEN_LOG_ERROR(LABEL, "softbus return null or empty string");
228 return "";
229 }
230
231 DeviceInfo info;
232 bool result = DeviceInfoManager::GetInstance().GetDeviceInfo(uuid, DeviceIdType::UNIVERSALLY_UNIQUE_ID, info);
233 if (result == false) {
234 ACCESSTOKEN_LOG_DEBUG(LABEL, "local device info not found for uuid");
235 } else {
236 std::string dimUuid = info.deviceId.universallyUniqueId;
237 if (uuid == dimUuid) {
238 // refresh cache
239 std::function<void()> fulfillDeviceInfo = std::bind(&SoftBusManager::FulfillLocalDeviceInfo, this);
240 std::thread fulfill(fulfillDeviceInfo);
241 fulfill.detach();
242 }
243 }
244
245 return uuid;
246 }
247
GetUniqueDeviceIdByNodeId(const std::string & nodeId)248 std::string SoftBusManager::GetUniqueDeviceIdByNodeId(const std::string &nodeId)
249 {
250 if (!DataValidator::IsDeviceIdValid(nodeId)) {
251 ACCESSTOKEN_LOG_ERROR(LABEL, "invalid nodeId");
252 return "";
253 }
254 std::string udid = GetUdidByNodeId(nodeId);
255 if (udid.empty()) {
256 ACCESSTOKEN_LOG_ERROR(LABEL, "softbus return null or empty string");
257 return "";
258 }
259 char localUdid[Constant::DEVICE_UUID_LENGTH] = {0};
260 ::GetDevUdid(localUdid, Constant::DEVICE_UUID_LENGTH);
261 if (udid == localUdid) {
262 // refresh cache
263 std::function<void()> fulfillDeviceInfo = std::bind(&SoftBusManager::FulfillLocalDeviceInfo, this);
264 std::thread fulfill(fulfillDeviceInfo);
265 fulfill.detach();
266 }
267 return udid;
268 }
269
GetUuidByNodeId(const std::string & nodeId) const270 std::string SoftBusManager::GetUuidByNodeId(const std::string &nodeId) const
271 {
272 uint8_t *info = new uint8_t[UDID_MAX_LENGTH + 1];
273 if (info == nullptr) {
274 ACCESSTOKEN_LOG_ERROR(LABEL, "no enough memory: %{public}d", UDID_MAX_LENGTH);
275 return "";
276 }
277 (void)memset_s(info, UDID_MAX_LENGTH + 1, 0, UDID_MAX_LENGTH + 1);
278 int32_t ret = ::GetNodeKeyInfo(ACCESS_TOKEN_PACKAGE_NAME.c_str(), nodeId.c_str(),
279 NodeDeviceInfoKey::NODE_KEY_UUID, info, UDID_MAX_LENGTH);
280 if (ret != Constant::SUCCESS) {
281 delete[] info;
282 ACCESSTOKEN_LOG_WARN(LABEL, "GetNodeKeyInfo error, return code: %{public}d", ret);
283 return "";
284 }
285 std::string uuid((char *) info);
286 delete[] info;
287 ACCESSTOKEN_LOG_DEBUG(LABEL, "call softbus finished");
288 return uuid;
289 }
290
GetUdidByNodeId(const std::string & nodeId) const291 std::string SoftBusManager::GetUdidByNodeId(const std::string &nodeId) const
292 {
293 uint8_t *info = new uint8_t[UDID_MAX_LENGTH + 1];
294 if (info == nullptr) {
295 ACCESSTOKEN_LOG_ERROR(LABEL, "no enough memory: %{public}d", UDID_MAX_LENGTH);
296 return "";
297 }
298 (void)memset_s(info, UDID_MAX_LENGTH + 1, 0, UDID_MAX_LENGTH + 1);
299 int32_t ret = ::GetNodeKeyInfo(ACCESS_TOKEN_PACKAGE_NAME.c_str(), nodeId.c_str(),
300 NodeDeviceInfoKey::NODE_KEY_UDID, info, UDID_MAX_LENGTH);
301 if (ret != Constant::SUCCESS) {
302 delete[] info;
303 ACCESSTOKEN_LOG_WARN(LABEL, "GetNodeKeyInfo error, code: %{public}d", ret);
304 return "";
305 }
306 std::string udid((char *) info);
307 delete[] info;
308 ACCESSTOKEN_LOG_DEBUG(LABEL, "call softbus finished");
309 return udid;
310 }
311
FulfillLocalDeviceInfo()312 int SoftBusManager::FulfillLocalDeviceInfo()
313 {
314 // repeated task will just skip
315 if (!fulfillMutex_.try_lock()) {
316 ACCESSTOKEN_LOG_INFO(LABEL, "FulfillLocalDeviceInfo already running, skip.");
317 return Constant::SUCCESS;
318 }
319
320 NodeBasicInfo info;
321 int32_t ret = ::GetLocalNodeDeviceInfo(ACCESS_TOKEN_PACKAGE_NAME.c_str(), &info);
322 if (ret != Constant::SUCCESS) {
323 ACCESSTOKEN_LOG_ERROR(LABEL, "GetLocalNodeDeviceInfo error");
324 fulfillMutex_.unlock();
325 return Constant::FAILURE;
326 }
327
328 ACCESSTOKEN_LOG_DEBUG(LABEL, "call softbus finished");
329
330 std::string uuid = GetUuidByNodeId(info.networkId);
331 std::string udid = GetUdidByNodeId(info.networkId);
332 if (uuid.empty() || udid.empty()) {
333 ACCESSTOKEN_LOG_ERROR(LABEL, "FulfillLocalDeviceInfo: uuid or udid is empty, abort.");
334 fulfillMutex_.unlock();
335 return Constant::FAILURE;
336 }
337
338 DeviceInfoManager::GetInstance().AddDeviceInfo(info.networkId, uuid, udid, info.deviceName,
339 std::to_string(info.deviceTypeId));
340 ACCESSTOKEN_LOG_DEBUG(LABEL, "AddDeviceInfo finished, networkId:%{public}s",
341 info.networkId);
342
343 fulfillMutex_.unlock();
344 return Constant::SUCCESS;
345 }
346 } // namespace AccessToken
347 } // namespace Security
348 } // namespace OHOS
349