1 /*
2  * Copyright (c) 2024 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 "dsched_all_connect_manager.h"
17 
18 #include <dlfcn.h>
19 
20 #include "distributed_sched_utils.h"
21 #include "dsched_transport_softbus_adapter.h"
22 #include "dtbschedmgr_log.h"
23 
24 namespace OHOS {
25 namespace DistributedSchedule {
26 namespace {
27 const std::string TAG = "DSchedAllConnectManager";
28 constexpr int32_t CONNECT_DECISION_WAIT_S = 60;
29 }
30 
31 IMPLEMENT_SINGLE_INSTANCE(DSchedAllConnectManager);
32 
33 ServiceCollaborationManager_HardwareRequestInfo DSchedAllConnectManager::locReqInfo_ = {
34     .hardWareType = ServiceCollaborationManagerHardwareType::SCM_DISPLAY,
35     .canShare = true,
36 };
37 ServiceCollaborationManager_HardwareRequestInfo DSchedAllConnectManager::rmtReqInfo_ = {
38     .hardWareType = ServiceCollaborationManagerHardwareType::SCM_DISPLAY,
39     .canShare = true,
40 };
41 ServiceCollaborationManager_CommunicationRequestInfo DSchedAllConnectManager::communicationRequest_ = {
42     .minBandwidth = DSCHED_QOS_TYPE_MIN_BW,
43     .maxLatency = DSCHED_QOS_TYPE_MAX_LATENCY,
44     .minLatency = DSCHED_QOS_TYPE_MIN_LATENCY,
45     .maxWaitTime = 0,
46     .dataType = "DATA_TYPE_BYTES",
47 };
48 std::queue<std::string> DSchedAllConnectManager::peerConnectCbQueue_;
49 
InitAllConnectManager()50 int32_t DSchedAllConnectManager::InitAllConnectManager()
51 {
52     HILOGI("Init bind manager.");
53     int32_t ret = GetServiceCollaborationManagerProxy();
54     if (ret != ERR_OK) {
55         HILOGE("GetServiceCollaborationManagerProxy fail, ret %{public}d.", ret);
56         return ret;
57     }
58 
59     ret = RegistLifecycleCallback();
60     if (ret != ERR_OK) {
61         HILOGE("Regist lifecycle callback fail, ret %{public}d.", ret);
62         return ret;
63     }
64     return ERR_OK;
65 }
66 
UninitAllConnectManager()67 int32_t DSchedAllConnectManager::UninitAllConnectManager()
68 {
69     HILOGI("Uninit bind manager enter.");
70     int32_t ret = UnregistLifecycleCallback();
71     if (ret != ERR_OK) {
72         HILOGE("Unregist lifecycle callback fail, ret %{public}d.", ret);
73     }
74     dlclose(dllHandle_);
75     dllHandle_ = nullptr;
76     allConnectMgrApi_ = {
77         .ServiceCollaborationManager_PublishServiceState = nullptr,
78         .ServiceCollaborationManager_ApplyAdvancedResource = nullptr,
79         .ServiceCollaborationManager_RegisterLifecycleCallback = nullptr,
80         .ServiceCollaborationManager_UnRegisterLifecycleCallback = nullptr,
81     };
82     return ERR_OK;
83 }
84 
GetServiceCollaborationManagerProxy()85 int32_t DSchedAllConnectManager::GetServiceCollaborationManagerProxy()
86 {
87     HILOGI("Get service collaboration manager proxy for all connect.");
88     std::lock_guard<std::mutex> autoLock(allConnectMgrLock_);
89 #if (defined(__aarch64__) || defined(__x86_64__))
90     std::string resolvedPath = "/system/lib64/libcfwk_allconnect_client.z.so";
91 #else
92     std::string resolvedPath = "/system/lib/libcfwk_allconnect_client.z.so";
93 #endif
94     char path[PATH_MAX + 1] = {0};
95     if (resolvedPath.length() > PATH_MAX || realpath(resolvedPath.c_str(), path) == nullptr) {
96         HILOGE("Check all connect so real path failed, resolvedPath [%{public}s].",
97             GetAnonymStr(resolvedPath).c_str());
98         return INVALID_PARAMETERS_ERR;
99     }
100     int32_t (*ServiceCollaborationManagerExport)(ServiceCollaborationManager_API *exportapi) = nullptr;
101 
102     dllHandle_ = dlopen(resolvedPath.c_str(), RTLD_LAZY);
103     if (dllHandle_ == nullptr) {
104         HILOGE("Open dms interactive adapter shared object fail, resolvedPath [%{public}s].",
105             GetAnonymStr(resolvedPath).c_str());
106         return NOT_FIND_SERVICE_REGISTRY;
107     }
108 
109     int32_t ret = ERR_OK;
110     do {
111         ServiceCollaborationManagerExport =
112             reinterpret_cast<int32_t (*)(ServiceCollaborationManager_API *exportapi)>(
113             dlsym(dllHandle_, "ServiceCollaborationManager_Export"));
114         if (ServiceCollaborationManagerExport == nullptr) {
115             HILOGE("Link the ServiceCollaborationManagerExport symbol in dms interactive adapter fail.");
116             ret = NOT_FIND_SERVICE_REGISTRY;
117             break;
118         }
119 
120         ret = ServiceCollaborationManagerExport(&allConnectMgrApi_);
121         if (ret != ERR_OK) {
122             HILOGE("Init remote dms interactive adapter proxy fail, ret %{public}d.", ret);
123             break;
124         }
125         HILOGI("Init remote dms interactive adapter proxy success.");
126     } while (false);
127 
128     if (ret != ERR_OK) {
129         HILOGE("Get remote dms interactive adapter proxy fail, dlclose handle.");
130         dlclose(dllHandle_);
131         dllHandle_ = nullptr;
132     }
133     return ret;
134 }
135 
RegistLifecycleCallback()136 int32_t DSchedAllConnectManager::RegistLifecycleCallback()
137 {
138     std::lock_guard<std::mutex> autoLock(allConnectMgrLock_);
139     HILOGI("Regist lifecycle callback.");
140     if (allConnectMgrApi_.ServiceCollaborationManager_RegisterLifecycleCallback == nullptr) {
141         HILOGE("Dms all connect manager RegisterLifecycleCallback api is null.");
142         return INVALID_PARAMETERS_ERR;
143     }
144 
145     ServiceCollaborationManager_Callback bindMgrRegLfCB = {
146         .OnStop = &DSchedAllConnectManager::OnStop,
147         .ApplyResult = &DSchedAllConnectManager::ApplyResult,
148     };
149 
150     int32_t ret = allConnectMgrApi_.ServiceCollaborationManager_RegisterLifecycleCallback(
151         DMS_BIND_MGR_SRV_NAME, &bindMgrRegLfCB);
152     if (ret != ERR_OK) {
153         HILOGE("Dms all connect manager regist lifecycle callback fail, ret %{public}d.", ret);
154     }
155     return ret;
156 }
157 
UnregistLifecycleCallback()158 int32_t DSchedAllConnectManager::UnregistLifecycleCallback()
159 {
160     std::lock_guard<std::mutex> autoLock(allConnectMgrLock_);
161     HILOGI("Unregist lifecycle callback.");
162     if (allConnectMgrApi_.ServiceCollaborationManager_UnRegisterLifecycleCallback == nullptr) {
163         HILOGE("Dms all connect manager UnRegisterLifecycleCallback api is null.");
164         return INVALID_PARAMETERS_ERR;
165     }
166 
167     int32_t ret = allConnectMgrApi_.ServiceCollaborationManager_UnRegisterLifecycleCallback(
168         DMS_BIND_MGR_SRV_NAME);
169     if (ret != ERR_OK) {
170         HILOGE("Dms all connect manager unregist lifecycle callback fail, ret %{public}d.", ret);
171     }
172     return ret;
173 }
174 
PublishServiceState(const std::string & peerNetworkId,const std::string & extraInfo,ServiceCollaborationManagerBussinessStatus state)175 int32_t DSchedAllConnectManager::PublishServiceState(const std::string &peerNetworkId, const std::string &extraInfo,
176     ServiceCollaborationManagerBussinessStatus state)
177 {
178     std::lock_guard<std::mutex> autoLock(allConnectMgrLock_);
179     HILOGI("Publish service state enter, peerNetworkId %{public}s, extraInfo %{public}s, state %{public}d.",
180         GetAnonymStr(peerNetworkId).c_str(), extraInfo.c_str(), state);
181     if (allConnectMgrApi_.ServiceCollaborationManager_PublishServiceState == nullptr) {
182         HILOGE("Dms all connect manager PublishServiceState api is null.");
183         return INVALID_PARAMETERS_ERR;
184     }
185 
186     int32_t ret = allConnectMgrApi_.ServiceCollaborationManager_PublishServiceState(peerNetworkId.c_str(),
187         DMS_BIND_MGR_SRV_NAME, extraInfo.c_str(), state);
188     if (ret != ERR_OK) {
189         HILOGE("Dms all connect manager publish service state fail, ret %{public}d.", ret);
190     }
191     return ret;
192 }
193 
ApplyAdvanceResource(const std::string & peerNetworkId,ServiceCollaborationManager_ResourceRequestInfoSets reqInfoSets)194 int32_t DSchedAllConnectManager::ApplyAdvanceResource(const std::string &peerNetworkId,
195     ServiceCollaborationManager_ResourceRequestInfoSets reqInfoSets)
196 {
197     int32_t ret = ERR_OK;
198     {
199         std::lock_guard<std::mutex> autoLock(allConnectMgrLock_);
200         HILOGI("Apply advance resource enter, peerNetworkId %{public}s.", GetAnonymStr(peerNetworkId).c_str());
201         if (allConnectMgrApi_.ServiceCollaborationManager_ApplyAdvancedResource == nullptr) {
202             HILOGE("Dms all connect manager ApplyAdvancedResource api is null.");
203             return ERR_OK;
204         }
205 
206         peerConnectCbQueue_.push(peerNetworkId);
207         ServiceCollaborationManager_Callback applyScmCbApi = {
208             .OnStop = &DSchedAllConnectManager::OnStop,
209             .ApplyResult = &DSchedAllConnectManager::ApplyResult,
210         };
211         ret = allConnectMgrApi_.ServiceCollaborationManager_ApplyAdvancedResource(peerNetworkId.c_str(),
212             DMS_BIND_MGR_SRV_NAME, &reqInfoSets, &applyScmCbApi);
213         if (ret != ERR_OK) {
214             HILOGE("Dms all connect manager apply advanced resource fail, ret %{public}d.", ret);
215             return ret;
216         }
217     }
218 
219     ret = WaitAllConnectApplyCb(peerNetworkId);
220     if (ret != ERR_OK) {
221         HILOGE("Wait all connect manager apply callback fail, ret %{public}d.", ret);
222     }
223     return ret;
224 }
225 
WaitAllConnectApplyCb(const std::string & peerNetworkId)226 int32_t DSchedAllConnectManager::WaitAllConnectApplyCb(const std::string &peerNetworkId)
227 {
228     std::unique_lock<std::mutex> decisionLock(connectDecisionMutex_);
229     connectDecisionCond_.wait_for(decisionLock, std::chrono::seconds(CONNECT_DECISION_WAIT_S),
230         [this, peerNetworkId]() {
231             return peerConnectDecision_.find(peerNetworkId) != peerConnectDecision_.end();
232         });
233 
234     if (peerConnectDecision_.find(peerNetworkId) == peerConnectDecision_.end()) {
235         HILOGE("Not find peerNetworkId %{public}s in peerConnectDecision.", GetAnonymStr(peerNetworkId).c_str());
236         return DMS_CONNECT_APPLY_TIMEOUT_FAILED;
237     }
238     int32_t ret = peerConnectDecision_.at(peerNetworkId).load() ? ERR_OK : DMS_CONNECT_APPLY_REJECT_FAILED;
239     HILOGI("Wait all connect apply decision callback end, peerNetworkId %{public}s, isSupport %{public}d.",
240         GetAnonymStr(peerNetworkId).c_str(), peerConnectDecision_.at(peerNetworkId).load());
241     peerConnectDecision_.erase(peerNetworkId);
242     return ret;
243 }
244 
NotifyAllConnectDecision(const std::string & peerNetworkId,bool isSupport)245 void DSchedAllConnectManager::NotifyAllConnectDecision(const std::string &peerNetworkId, bool isSupport)
246 {
247     HILOGI("Notify all connect decision, peerNetworkId %{public}s, isSupport %{public}d.",
248         GetAnonymStr(peerNetworkId).c_str(), isSupport);
249     std::lock_guard<std::mutex> decisionLock(connectDecisionMutex_);
250     peerConnectDecision_[peerNetworkId] = isSupport;
251     connectDecisionCond_.notify_all();
252 }
253 
GetResourceRequest(ServiceCollaborationManager_ResourceRequestInfoSets & reqInfoSets)254 void DSchedAllConnectManager::GetResourceRequest(ServiceCollaborationManager_ResourceRequestInfoSets &reqInfoSets)
255 {
256     reqInfoSets.remoteHardwareListSize = 1;
257     reqInfoSets.remoteHardwareList = &rmtReqInfo_;
258     reqInfoSets.localHardwareListSize = 1;
259     reqInfoSets.localHardwareList = &locReqInfo_;
260     reqInfoSets.communicationRequest = &communicationRequest_;
261 }
262 
OnStop(const char * peerNetworkId)263 int32_t DSchedAllConnectManager::OnStop(const char *peerNetworkId)
264 {
265     HILOGI("OnStop, when other task prepare to seize bind, disconnect DMS bind with peerNetworkId %{public}s.",
266         GetAnonymStr(peerNetworkId).c_str());
267     int32_t sessionId = -1;
268     if (!DSchedTransportSoftbusAdapter::GetInstance().GetSessionIdByDeviceId(peerNetworkId, sessionId)) {
269         HILOGW("Not find any sessionId by peerNetworkId %{public}s.", GetAnonymStr(peerNetworkId).c_str());
270         return ERR_OK;
271     }
272     DSchedTransportSoftbusAdapter::GetInstance().OnShutdown(sessionId, false);
273     return ERR_OK;
274 }
275 
ApplyResult(int32_t errorcode,int32_t result,const char * reason)276 int32_t DSchedAllConnectManager::ApplyResult(int32_t errorcode, int32_t result, const char *reason)
277 {
278     HILOGI("Apply result start, errorcode %{public}d, result %{public}s, reason %{public}s.",
279         errorcode, result == ServiceCollaborationManagerResultCode::PASS ? "PASS" : "REJECT", reason);
280 
281     bool isSupport = result == ServiceCollaborationManagerResultCode::PASS ? true : false;
282     if (peerConnectCbQueue_.empty()) {
283         HILOGE("Apply result start, peerConnectCbQueue is empty.");
284         return ERR_OK;
285     }
286     std::string peerNetworkId = peerConnectCbQueue_.front();
287     DSchedAllConnectManager::GetInstance().NotifyAllConnectDecision(peerNetworkId, isSupport);
288     peerConnectCbQueue_.pop();
289     return ERR_OK;
290 }
291 } // namespace DistributedSchedule
292 } // namespace OHOS