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 "dh_comm_tool.h"
17 
18 #include "cJSON.h"
19 
20 #include "anonymous_string.h"
21 #include "capability_info_manager.h"
22 #include "component_manager.h"
23 #include "dh_context.h"
24 #include "dh_transport_obj.h"
25 #include "dh_utils_tool.h"
26 #include "distributed_hardware_errno.h"
27 #include "distributed_hardware_log.h"
28 #include "local_capability_info_manager.h"
29 #include "task_executor.h"
30 
31 namespace OHOS {
32 namespace DistributedHardware {
33 #undef DH_LOG_TAG
34 #define DH_LOG_TAG "DHCommTool"
35 
DHCommTool()36 DHCommTool::DHCommTool() : dhTransportPtr_(nullptr)
37 {
38     DHLOGI("Ctor DHCommTool");
39 }
40 
Init()41 void DHCommTool::Init()
42 {
43     DHLOGI("Init DHCommTool");
44     dhTransportPtr_ = std::make_shared<DHTransport>(shared_from_this());
45     std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create(true);
46     eventHandler_ = std::make_shared<DHCommTool::DHCommToolEventHandler>(runner, shared_from_this());
47     dhTransportPtr_->Init();
48 }
49 
UnInit()50 void DHCommTool::UnInit()
51 {
52     DHLOGI("UnInit DHCommTool");
53     if (dhTransportPtr_ == nullptr) {
54         DHLOGI("dhTransportPtr_ is null");
55         return;
56     }
57     dhTransportPtr_->UnInit();
58 }
59 
GetInstance()60 std::shared_ptr<DHCommTool> DHCommTool::GetInstance()
61 {
62     static std::shared_ptr<DHCommTool> instance = std::make_shared<DHCommTool>();
63     return instance;
64 }
65 
TriggerReqFullDHCaps(const std::string & remoteNetworkId)66 void DHCommTool::TriggerReqFullDHCaps(const std::string &remoteNetworkId)
67 {
68     DHLOGI("TriggerReqFullDHCaps, remote networkId: %{public}s", GetAnonyString(remoteNetworkId).c_str());
69     if (remoteNetworkId.empty() || dhTransportPtr_ == nullptr) {
70         DHLOGE("remoteNetworkId or transport is null");
71         return;
72     }
73     std::string localNetworkId = GetLocalNetworkId();
74     if (localNetworkId.empty()) {
75         DHLOGE("Get local network id error");
76         return;
77     }
78     if (dhTransportPtr_->StartSocket(remoteNetworkId) != DH_FWK_SUCCESS) {
79         DHLOGE("Start socket error");
80         return;
81     }
82     CommMsg commMsg(DH_COMM_REQ_FULL_CAPS, localNetworkId);
83     std::string payload = GetCommMsgString(commMsg);
84 
85     int32_t ret = dhTransportPtr_->Send(remoteNetworkId, payload);
86     if (ret != DH_FWK_SUCCESS) {
87         DHLOGE("Trigger req remote full attrs error");
88         return;
89     }
90     DHLOGI("Trigger req remote full attrs success.");
91 }
92 
GetAndSendLocalFullCaps(const std::string & reqNetworkId)93 void DHCommTool::GetAndSendLocalFullCaps(const std::string &reqNetworkId)
94 {
95     DHLOGI("GetAndSendLocalFullCaps, reqNetworkId: %{public}s", GetAnonyString(reqNetworkId).c_str());
96     if (dhTransportPtr_ == nullptr) {
97         DHLOGE("transport is null");
98         return;
99     }
100     std::string localDeviceId = DHContext::GetInstance().GetDeviceInfo().deviceId;
101     std::vector<std::shared_ptr<CapabilityInfo>> resInfos;
102     CapabilityInfoManager::GetInstance()->GetCapabilitiesByDeviceId(localDeviceId, resInfos);
103     FullCapsRsp capsRsp;
104     capsRsp.networkId = GetLocalNetworkId();
105     capsRsp.caps = resInfos;
106     cJSON *root = cJSON_CreateObject();
107     if (root == nullptr) {
108         DHLOGE("Create cJSON object failed.");
109         return;
110     }
111     ToJson(root, capsRsp);
112     char *msg = cJSON_PrintUnformatted(root);
113     if (msg == nullptr) {
114         cJSON_Delete(root);
115         return;
116     }
117     std::string fullCapsMsg(msg);
118     cJSON_free(msg);
119     cJSON_Delete(root);
120 
121     CommMsg commMsg(DH_COMM_RSP_FULL_CAPS, fullCapsMsg);
122     std::string payload = GetCommMsgString(commMsg);
123 
124     int32_t ret = dhTransportPtr_->Send(reqNetworkId, payload);
125     if (ret != DH_FWK_SUCCESS) {
126         DHLOGE("Send back Caps failed, ret: %{public}d", ret);
127         return;
128     }
129     DHLOGI("Send back Caps success");
130 }
131 
ParseAndSaveRemoteDHCaps(const std::string & remoteCaps)132 FullCapsRsp DHCommTool::ParseAndSaveRemoteDHCaps(const std::string &remoteCaps)
133 {
134     FullCapsRsp capsRsp;
135     DHLOGI("ParseAndSaveRemoteDHCaps enter");
136     cJSON *root = cJSON_Parse(remoteCaps.c_str());
137     if (root == NULL) {
138         DHLOGE("Parse remote Caps failed");
139         return capsRsp;
140     }
141 
142     FromJson(root, capsRsp);
143     cJSON_Delete(root);
144     int32_t ret = LocalCapabilityInfoManager::GetInstance()->AddCapability(capsRsp.caps);
145     if (ret != DH_FWK_SUCCESS) {
146         DHLOGE("Save local capabilities error, ret: %{public}d", ret);
147         return capsRsp;
148     }
149     DHLOGE("Save local capabilities success");
150     return capsRsp;
151 }
152 
DHCommToolEventHandler(const std::shared_ptr<AppExecFwk::EventRunner> runner,std::shared_ptr<DHCommTool> dhCommToolPtr)153 DHCommTool::DHCommToolEventHandler::DHCommToolEventHandler(const std::shared_ptr<AppExecFwk::EventRunner> runner,
154     std::shared_ptr<DHCommTool> dhCommToolPtr) : AppExecFwk::EventHandler(runner), dhCommToolWPtr_(dhCommToolPtr)
155 {
156     DHLOGI("Ctor DHCommToolEventHandler");
157 }
158 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)159 void DHCommTool::DHCommToolEventHandler::ProcessEvent(
160     const AppExecFwk::InnerEvent::Pointer &event)
161 {
162     uint32_t eventId = event->GetInnerEventId();
163     std::shared_ptr<CommMsg> commMsg = event->GetSharedObject<CommMsg>();
164     if (commMsg == nullptr) {
165         DHLOGE("ProcessEvent commMsg is null");
166         return;
167     }
168     if (dhCommToolWPtr_.expired()) {
169         DHLOGE("dhCommToolWPtr_ is expired");
170         return;
171     }
172     std::shared_ptr<DHCommTool> dhCommToolPtr = dhCommToolWPtr_.lock();
173     if (dhCommToolPtr == nullptr) {
174         DHLOGE("dhCommToolPtr is null");
175         return;
176     }
177     switch (eventId) {
178         case DH_COMM_REQ_FULL_CAPS: {
179             dhCommToolPtr->GetAndSendLocalFullCaps(commMsg->msg);
180             break;
181         }
182         case DH_COMM_RSP_FULL_CAPS: {
183             // parse remote rsp full attrs and save to local db
184             FullCapsRsp capsRsp = dhCommToolPtr->ParseAndSaveRemoteDHCaps(commMsg->msg);
185             DHLOGI("Receive full remote capabilities, remote networkid: %{public}s, caps size: %{public}" PRIu32,
186                 GetAnonyString(capsRsp.networkId).c_str(), static_cast<uint32_t>(capsRsp.caps.size()));
187             ProcessFullCapsRsp(capsRsp, dhCommToolPtr);
188             break;
189         }
190         default:
191             DHLOGE("event is undefined, id is %{public}d", eventId);
192             break;
193     }
194 }
195 
ProcessFullCapsRsp(const FullCapsRsp & capsRsp,const std::shared_ptr<DHCommTool> dhCommToolPtr)196 void DHCommTool::DHCommToolEventHandler::ProcessFullCapsRsp(const FullCapsRsp &capsRsp,
197     const std::shared_ptr<DHCommTool> dhCommToolPtr)
198 {
199     if (capsRsp.networkId.empty() || capsRsp.caps.empty()) {
200         DHLOGE("Receive remote caps info invalid!");
201         return;
202     }
203     // after receive rsp, close dsoftbus channel
204     DHLOGI("we receive full remote capabilities, close channel, remote networkId: %{public}s",
205         GetAnonyString(capsRsp.networkId).c_str());
206     dhCommToolPtr->GetDHTransportPtr()->StopSocket(capsRsp.networkId);
207 
208     // trigger register dh by full attrs
209     std::string uuid = DHContext::GetInstance().GetUUIDByNetworkId(capsRsp.networkId);
210     if (uuid.empty()) {
211         DHLOGE("Can not find remote device uuid by networkid: %{public}s", GetAnonyString(capsRsp.networkId).c_str());
212         return;
213     }
214 
215     for (auto const &cap : capsRsp.caps) {
216         BusinessState curState = ComponentManager::GetInstance().QueryBusinessState(capsRsp.networkId, cap->GetDHId());
217         DHLOGI("DH state: %{public}" PRIu32 ", networkId: %{public}s, dhId: %{public}s",
218             (uint32_t)curState, GetAnonyString(capsRsp.networkId).c_str(), GetAnonyString(cap->GetDHId()).c_str());
219         TaskParam taskParam = {
220             .networkId = capsRsp.networkId,
221             .uuid = uuid,
222             .dhId = cap->GetDHId(),
223             .dhType = cap->GetDHType()
224         };
225         if (curState != BusinessState::RUNNING && curState != BusinessState::PAUSING) {
226             DHLOGI("The dh not busy, refresh it");
227             auto task = TaskFactory::GetInstance().CreateTask(TaskType::ENABLE, taskParam, nullptr);
228             TaskExecutor::GetInstance().PushTask(task);
229         } else {
230             DHLOGI("The dh busy, save and refresh after idle");
231             ComponentManager::GetInstance().SaveNeedRefreshTask(taskParam);
232         }
233     }
234 }
235 
GetEventHandler()236 std::shared_ptr<DHCommTool::DHCommToolEventHandler> DHCommTool::GetEventHandler()
237 {
238     return this->eventHandler_;
239 }
240 
GetDHTransportPtr()241 const std::shared_ptr<DHTransport> DHCommTool::GetDHTransportPtr()
242 {
243     return this->dhTransportPtr_;
244 }
245 
246 } // DistributedHardware
247 } // OHOS