1 /*
2  * Copyright (c) 2021-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 "distributed_input_handler.h"
17 
18 #include <cstring>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <pthread.h>
22 #include <sstream>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 
26 #include <openssl/sha.h>
27 #include <sys/inotify.h>
28 #include <linux/input.h>
29 #include <linux/uinput.h>
30 
31 #include "nlohmann/json.hpp"
32 
33 #include "constants_dinput.h"
34 #include "dinput_errcode.h"
35 #include "dinput_log.h"
36 #include "dinput_softbus_define.h"
37 #include "dinput_utils_tool.h"
38 #include "softbus_bus_center.h"
39 
40 namespace OHOS {
41 namespace DistributedHardware {
42 namespace DistributedInput {
43 IMPLEMENT_SINGLE_INSTANCE(DistributedInputHandler);
DistributedInputHandler()44 DistributedInputHandler::DistributedInputHandler()
45     : collectThreadID_(-1), isCollectingEvents_(false), isStartCollectEventThread_(false)
46 {
47     inputHub_ = std::make_unique<InputHub>(true);
48     this->m_listener = nullptr;
49 }
50 
~DistributedInputHandler()51 DistributedInputHandler::~DistributedInputHandler()
52 {
53     StopInputMonitorDeviceThread();
54 }
55 
StructTransJson(const InputDevice & pBuf,std::string & strDescriptor)56 void DistributedInputHandler::StructTransJson(const InputDevice &pBuf, std::string &strDescriptor)
57 {
58     DHLOGI("[%{public}s] %{public}d, %{public}d, %{public}d, %{public}d, %{public}s.\n", (pBuf.name).c_str(),
59         pBuf.bus, pBuf.vendor, pBuf.product, pBuf.version, GetAnonyString(pBuf.descriptor).c_str());
60     nlohmann::json tmpJson;
61     tmpJson[DEVICE_NAME] = pBuf.name;
62     tmpJson[PHYSICAL_PATH] = pBuf.physicalPath;
63     tmpJson[UNIQUE_ID] = pBuf.uniqueId;
64     tmpJson[BUS] = pBuf.bus;
65     tmpJson[VENDOR] = pBuf.vendor;
66     tmpJson[PRODUCT] = pBuf.product;
67     tmpJson[VERSION] = pBuf.version;
68     tmpJson[DESCRIPTOR] = pBuf.descriptor;
69     tmpJson[CLASSES] = pBuf.classes;
70     tmpJson[EVENT_TYPES] = pBuf.eventTypes;
71     tmpJson[EVENT_KEYS] = pBuf.eventKeys;
72     tmpJson[ABS_TYPES] = pBuf.absTypes;
73     tmpJson[ABS_INFOS] = pBuf.absInfos;
74     tmpJson[REL_TYPES] = pBuf.relTypes;
75     tmpJson[PROPERTIES] = pBuf.properties;
76 
77     tmpJson[MISCELLANEOUS] = pBuf.miscellaneous;
78     tmpJson[LEDS] = pBuf.leds;
79     tmpJson[REPEATS] = pBuf.repeats;
80     tmpJson[SWITCHS] = pBuf.switchs;
81 
82     std::ostringstream stream;
83     stream << tmpJson.dump();
84     strDescriptor = stream.str();
85     DHLOGI("Record InputDevice json info: %{public}s", strDescriptor.c_str());
86     return;
87 }
88 
Initialize()89 int32_t DistributedInputHandler::Initialize()
90 {
91     if (!isStartCollectEventThread_) {
92         InitCollectEventsThread();
93         isStartCollectEventThread_ = true;
94     }
95     return DH_SUCCESS;
96 }
97 
FindDevicesInfoByType(const uint32_t inputTypes,std::map<int32_t,std::string> & datas)98 void DistributedInputHandler::FindDevicesInfoByType(const uint32_t inputTypes, std::map<int32_t, std::string> &datas)
99 {
100     if (inputHub_ != nullptr) {
101         inputHub_->GetDevicesInfoByType(inputTypes, datas);
102     }
103 }
104 
FindDevicesInfoByDhId(std::vector<std::string> dhidsVec,std::map<int32_t,std::string> & datas)105 void DistributedInputHandler::FindDevicesInfoByDhId(
106     std::vector<std::string> dhidsVec, std::map<int32_t, std::string> &datas)
107 {
108     if (inputHub_ != nullptr) {
109         inputHub_->GetDevicesInfoByDhId(dhidsVec, datas);
110     }
111 }
112 
QueryMeta()113 std::vector<DHItem> DistributedInputHandler::QueryMeta()
114 {
115     return {};
116 }
117 
Query()118 std::vector<DHItem> DistributedInputHandler::Query()
119 {
120     std::vector<DHItem> retInfos;
121 
122     if (inputHub_ != nullptr) {
123         std::vector<InputDevice> vecInput = inputHub_->GetAllInputDevices();
124         for (auto iter : vecInput) {
125             DHItem item;
126             item.dhId = iter.descriptor;
127             item.subtype = "input";
128             StructTransJson(iter, item.attrs);
129             retInfos.push_back(item);
130         }
131     }
132 
133     return retInfos;
134 }
135 
QueryExtraInfo()136 std::map<std::string, std::string> DistributedInputHandler::QueryExtraInfo()
137 {
138     std::map<std::string, std::string> ret;
139     return ret;
140 }
141 
IsSupportPlugin()142 bool DistributedInputHandler::IsSupportPlugin()
143 {
144     return true;
145 }
146 
RegisterPluginListener(std::shared_ptr<PluginListener> listener)147 void DistributedInputHandler::RegisterPluginListener(std::shared_ptr<PluginListener> listener)
148 {
149     this->m_listener = listener;
150 }
151 
UnRegisterPluginListener()152 void DistributedInputHandler::UnRegisterPluginListener()
153 {
154     this->m_listener = nullptr;
155 }
156 
InitCollectEventsThread()157 bool DistributedInputHandler::InitCollectEventsThread()
158 {
159     pthread_attr_t attr;
160     pthread_attr_init(&attr);
161     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
162 
163     isCollectingEvents_ = true;
164     collectThreadID_ = -1;
165     int32_t ret = pthread_create(&collectThreadID_, &attr, CollectEventsThread, this);
166     if (ret != 0) {
167         DHLOGE("DistributedInputHandler::InitCollectEventsThread create thread failed:%{public}d \n", ret);
168         pthread_attr_destroy(&attr);
169         collectThreadID_ = -1;
170         isCollectingEvents_ = false;
171         return false;
172     }
173     return true;
174 }
175 
CollectEventsThread(void * param)176 void *DistributedInputHandler::CollectEventsThread(void *param)
177 {
178     int32_t ret = pthread_setname_np(pthread_self(), COLLECT_EVENT_THREAD_NAME);
179     if (ret != 0) {
180         DHLOGE("CollectEventsThread setname failed.");
181     }
182     DistributedInputHandler *pThis = reinterpret_cast<DistributedInputHandler *>(param);
183     if (pThis == nullptr) {
184         DHLOGE("pThis is null.");
185         return nullptr;
186     }
187     pThis->StartInputMonitorDeviceThread();
188     DHLOGI("DistributedInputHandler::CollectEventsThread exist!");
189     return nullptr;
190 }
191 
StartInputMonitorDeviceThread()192 void DistributedInputHandler::StartInputMonitorDeviceThread()
193 {
194     if (inputHub_ == nullptr) {
195         DHLOGE("inputHub_ not initialized");
196         return;
197     }
198     while (isCollectingEvents_) {
199         size_t count = inputHub_->StartCollectInputHandler(mEventBuffer_, inputDeviceBufferSize_);
200         if (count > 0) {
201             DHLOGI("Count: %{public}zu", count);
202             for (size_t iCnt = 0; iCnt < count; iCnt++) {
203                 NotifyHardWare(iCnt);
204             }
205         } else {
206             continue;
207         }
208     }
209     isCollectingEvents_ = false;
210     DHLOGI("DistributedInputHandler::StartCollectEventsThread exit!");
211 }
212 
NotifyHardWare(int iCnt)213 void DistributedInputHandler::NotifyHardWare(int iCnt)
214 {
215     switch (mEventBuffer_[iCnt].type) {
216         case DeviceType::DEVICE_ADDED:
217             if (this->m_listener != nullptr) {
218                 std::string hdInfo;
219                 StructTransJson(mEventBuffer_[iCnt].deviceInfo, hdInfo);
220                 std::string subtype = "input";
221                 this->m_listener->PluginHardware(mEventBuffer_[iCnt].deviceInfo.descriptor, hdInfo, subtype);
222             }
223             break;
224         case DeviceType::DEVICE_REMOVED:
225             if (this->m_listener != nullptr) {
226                 this->m_listener->UnPluginHardware(mEventBuffer_[iCnt].deviceInfo.descriptor);
227             }
228             break;
229         default:
230             break;
231     }
232 }
233 
StopInputMonitorDeviceThread()234 void DistributedInputHandler::StopInputMonitorDeviceThread()
235 {
236     if (inputHub_ == nullptr) {
237         DHLOGE("inputHub_ not initialized");
238         return;
239     }
240     isCollectingEvents_ = false;
241     isStartCollectEventThread_ = false;
242     inputHub_->StopCollectInputHandler();
243     if (collectThreadID_ != (pthread_t)(-1)) {
244         DHLOGI("DistributedInputHandler::Wait collect thread exit");
245         pthread_join(collectThreadID_, NULL);
246         collectThreadID_ = (pthread_t)(-1);
247     }
248     DHLOGI("DistributedInputHandler::StopInputMonitorDeviceThread exit!");
249 }
250 
GetHardwareHandler()251 IHardwareHandler* GetHardwareHandler()
252 {
253     return &DistributedInputHandler::GetInstance();
254 }
255 } // namespace DistributedInput
256 } // namespace DistributedHardware
257 } // namespace OHOS
258