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
16#include "bluetooth_hid_host.h"
17#include <unistd.h>
18#include "bluetooth_device.h"
19#include "bluetooth_host.h"
20#include "bluetooth_profile_manager.h"
21#include "bluetooth_log.h"
22#include "bluetooth_observer_list.h"
23#include "bluetooth_hid_host_observer_stub.h"
24#include "bluetooth_utils.h"
25#include "i_bluetooth_hid_host.h"
26#include "i_bluetooth_host.h"
27#include "iservice_registry.h"
28#include "system_ability_definition.h"
29
30namespace OHOS {
31namespace Bluetooth {
32std::mutex g_hidProxyMutex;
33class HidHostInnerObserver : public BluetoothHidHostObserverStub {
34public:
35    explicit HidHostInnerObserver(BluetoothObserverList<HidHostObserver> &observers) : observers_(observers)
36    {
37        HILOGD("Enter!");
38    }
39    ~HidHostInnerObserver() override
40    {
41        HILOGD("Enter!");
42    }
43
44    ErrCode OnConnectionStateChanged(const BluetoothRawAddress &device, int32_t state, int32_t cause) override
45    {
46        HILOGD("hid conn state, device: %{public}s, state: %{public}s, cause: %{public}d",
47            GET_ENCRYPT_RAW_ADDR(device), GetProfileConnStateName(state).c_str(), cause);
48        BluetoothRemoteDevice remoteDevice(device.GetAddress(), 0);
49        observers_.ForEach([remoteDevice, state, cause](std::shared_ptr<HidHostObserver> observer) {
50            observer->OnConnectionStateChanged(remoteDevice, state, cause);
51        });
52        return NO_ERROR;
53    }
54
55private:
56    BluetoothObserverList<HidHostObserver> &observers_;
57    BLUETOOTH_DISALLOW_COPY_AND_ASSIGN(HidHostInnerObserver);
58};
59
60struct HidHost::impl {
61    impl();
62    ~impl();
63
64    int32_t GetDevicesByStates(std::vector<int> states, std::vector<BluetoothRemoteDevice>& result)
65    {
66        HILOGI("Enter!");
67        std::vector<BluetoothRawAddress> rawDevices;
68        std::vector<int32_t> tmpStates;
69        for (int32_t state : states) {
70            tmpStates.push_back((int32_t)state);
71        }
72        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
73        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_SERVICE_DISCONNECTED, "failed: no proxy");
74        int32_t ret = proxy->GetDevicesByStates(tmpStates, rawDevices);
75        if (ret != BT_NO_ERROR) {
76            HILOGE("inner error.");
77            return ret;
78        }
79
80        for (BluetoothRawAddress rawDevice : rawDevices) {
81            BluetoothRemoteDevice remoteDevice(rawDevice.GetAddress(), 1);
82            result.push_back(remoteDevice);
83        }
84
85        return BT_NO_ERROR;
86    }
87
88    int32_t GetDeviceState(const BluetoothRemoteDevice &device, int32_t &state)
89    {
90        HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
91        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
92        if (proxy == nullptr || !device.IsValidBluetoothRemoteDevice()) {
93            HILOGE("invalid param.");
94            return BT_ERR_INVALID_PARAM;
95        }
96
97        return proxy->GetDeviceState(BluetoothRawAddress(device.GetDeviceAddr()), state);
98    }
99
100    int32_t Connect(const BluetoothRemoteDevice &device)
101    {
102        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
103        if (proxy == nullptr || !device.IsValidBluetoothRemoteDevice()) {
104            HILOGE("invalid param.");
105            return BT_ERR_INVALID_PARAM;
106        }
107        HILOGI("hid connect remote device: %{public}s", GET_ENCRYPT_ADDR(device));
108        return proxy->Connect(BluetoothRawAddress(device.GetDeviceAddr()));
109    }
110
111    int32_t Disconnect(const BluetoothRemoteDevice &device)
112    {
113        HILOGI("hid disconnect remote device: %{public}s", GET_ENCRYPT_ADDR(device));
114        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
115        if (proxy == nullptr || !device.IsValidBluetoothRemoteDevice()) {
116            HILOGE("invalid param.");
117            return BT_ERR_INVALID_PARAM;
118        }
119
120        return proxy->Disconnect(BluetoothRawAddress(device.GetDeviceAddr()));
121    }
122
123    void RegisterObserver(std::shared_ptr<HidHostObserver> observer)
124    {
125        HILOGD("Enter!");
126        observers_.Register(observer);
127    }
128
129    void DeregisterObserver(std::shared_ptr<HidHostObserver> observer)
130    {
131        HILOGI("Enter!");
132        observers_.Deregister(observer);
133    }
134
135    void HidHostVCUnplug(std::string device, uint8_t id, uint16_t size, uint8_t type)
136    {
137        HILOGI("Enter!");
138        int result;
139        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
140        if (proxy != nullptr) {
141            proxy->HidHostVCUnplug(device, id, size, type, result);
142        }
143    }
144
145    void HidHostSendData(std::string device, uint8_t id, uint16_t size, uint8_t type)
146    {
147        HILOGI("Enter!");
148        int result;
149        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
150        if (proxy != nullptr) {
151            proxy->HidHostSendData(device, id, size, type, result);
152        }
153    }
154
155    void HidHostSetReport(std::string device, uint8_t type, std::string &report)
156    {
157        HILOGI("Enter!");
158        int result;
159        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
160        if (proxy != nullptr) {
161            proxy->HidHostSetReport(device, type, report, result);
162        }
163    }
164
165    void HidHostGetReport(std::string device, uint8_t id, uint16_t size, uint8_t type)
166    {
167        HILOGI("Enter!");
168        int result;
169        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
170        if (proxy != nullptr && IS_BT_ENABLED()) {
171            proxy->HidHostGetReport(device, id, size, type, result);
172        }
173    }
174
175    int SetConnectStrategy(const BluetoothRemoteDevice &device, int strategy)
176    {
177        HILOGI("enter");
178        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
179        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
180        return proxy->SetConnectStrategy(BluetoothRawAddress(device.GetDeviceAddr()), strategy);
181    }
182
183    int GetConnectStrategy(const BluetoothRemoteDevice &device, int &strategy) const
184    {
185        HILOGI("enter");
186        sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
187        CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
188        return proxy->GetConnectStrategy(BluetoothRawAddress(device.GetDeviceAddr()), strategy);
189    }
190
191    int32_t profileRegisterId = 0;
192private:
193    BluetoothObserverList<HidHostObserver> observers_;
194    sptr<HidHostInnerObserver> innerObserver_;
195};
196
197HidHost::impl::impl()
198{
199    innerObserver_ = new HidHostInnerObserver(observers_);
200    profileRegisterId = BluetoothProfileManager::GetInstance().RegisterFunc(PROFILE_HID_HOST_SERVER,
201        [this](sptr<IRemoteObject> remote) {
202        sptr<IBluetoothHidHost> proxy = iface_cast<IBluetoothHidHost>(remote);
203        CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
204        proxy->RegisterObserver(innerObserver_);
205    });
206}
207
208HidHost::impl::~impl()
209{
210    HILOGD("start");
211    BluetoothProfileManager::GetInstance().DeregisterFunc(profileRegisterId);
212    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
213    CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
214    proxy->DeregisterObserver(innerObserver_);
215}
216
217HidHost::HidHost()
218{
219    pimpl = std::make_unique<impl>();
220}
221
222HidHost::~HidHost() {}
223
224HidHost *HidHost::GetProfile()
225{
226#ifdef DTFUZZ_TEST
227    static BluetoothNoDestructor<HidHost> instance;
228    return instance.get();
229#else
230    static HidHost instance;
231    return &instance;
232#endif
233}
234
235int32_t HidHost::GetDevicesByStates(std::vector<int> states, std::vector<BluetoothRemoteDevice> &result)
236{
237    if (!IS_BT_ENABLED()) {
238        HILOGE("bluetooth is off.");
239        return BT_ERR_INVALID_STATE;
240    }
241
242    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
243    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
244
245    return pimpl->GetDevicesByStates(states, result);
246}
247
248int32_t HidHost::GetDeviceState(const BluetoothRemoteDevice &device, int32_t &state)
249{
250    if (!IS_BT_ENABLED()) {
251        HILOGE("bluetooth is off.");
252        return BT_ERR_INVALID_STATE;
253    }
254
255    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
256    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
257
258    return pimpl->GetDeviceState(device, state);
259}
260
261int32_t HidHost::Connect(const BluetoothRemoteDevice &device)
262{
263    if (!IS_BT_ENABLED()) {
264        HILOGE("bluetooth is off.");
265        return BT_ERR_INVALID_STATE;
266    }
267
268    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
269    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
270
271    return pimpl->Connect(device);
272}
273
274int32_t HidHost::Disconnect(const BluetoothRemoteDevice &device)
275{
276    if (!IS_BT_ENABLED()) {
277        HILOGE("bluetooth is off.");
278        return BT_ERR_INVALID_STATE;
279    }
280
281    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
282    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
283
284    return pimpl->Disconnect(device);
285}
286
287int HidHost::SetConnectStrategy(const BluetoothRemoteDevice &device, int strategy)
288{
289    HILOGI("enter, device: %{public}s, strategy: %{public}d", GET_ENCRYPT_ADDR(device), strategy);
290    if (!IS_BT_ENABLED()) {
291        HILOGE("bluetooth is off.");
292        return BT_ERR_INVALID_STATE;
293    }
294
295    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
296    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
297
298    if ((!device.IsValidBluetoothRemoteDevice()) || (
299        (strategy != static_cast<int>(BTStrategyType::CONNECTION_ALLOWED)) &&
300        (strategy != static_cast<int>(BTStrategyType::CONNECTION_FORBIDDEN)))) {
301        HILOGI("input parameter error.");
302        return BT_ERR_INVALID_PARAM;
303    }
304    return pimpl->SetConnectStrategy(device, strategy);
305}
306
307int HidHost::GetConnectStrategy(const BluetoothRemoteDevice &device, int &strategy) const
308{
309    HILOGI("enter, device: %{public}s", GET_ENCRYPT_ADDR(device));
310    if (!IS_BT_ENABLED()) {
311        HILOGE("bluetooth is off.");
312        return BT_ERR_INVALID_STATE;
313    }
314
315    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
316    CHECK_AND_RETURN_LOG_RET(proxy != nullptr, BT_ERR_UNAVAILABLE_PROXY, "failed: no proxy");
317
318    if (!device.IsValidBluetoothRemoteDevice()) {
319        HILOGI("input parameter error.");
320        return BT_ERR_INVALID_PARAM;
321    }
322    return pimpl->GetConnectStrategy(device, strategy);
323}
324
325void HidHost::RegisterObserver(std::shared_ptr<HidHostObserver> observer)
326{
327    HILOGD("enter");
328    CHECK_AND_RETURN_LOG(pimpl != nullptr, "pimpl is null.");
329    pimpl->RegisterObserver(observer);
330}
331
332void HidHost::DeregisterObserver(std::shared_ptr<HidHostObserver> observer)
333{
334    HILOGD("enter");
335    CHECK_AND_RETURN_LOG(pimpl != nullptr, "pimpl is null.");
336    pimpl->DeregisterObserver(observer);
337}
338
339void HidHost::HidHostVCUnplug(std::string device, uint8_t id, uint16_t size, uint8_t type)
340{
341    if (!IS_BT_ENABLED()) {
342        HILOGE("bluetooth is off.");
343        return;
344    }
345    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
346    CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
347
348    return pimpl->HidHostVCUnplug(device, id, size, type);
349}
350
351void HidHost::HidHostSendData(std::string device, uint8_t id, uint16_t size, uint8_t type)
352{
353    if (!IS_BT_ENABLED()) {
354        HILOGE("bluetooth is off.");
355        return;
356    }
357    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
358    CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
359
360    return pimpl->HidHostSendData(device, id, size, type);
361}
362
363void HidHost::HidHostSetReport(std::string device, uint8_t type, std::string &report)
364{
365    if (!IS_BT_ENABLED()) {
366        HILOGE("bluetooth is off.");
367        return;
368    }
369    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
370    CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
371
372    return pimpl->HidHostSetReport(device, type, report);
373}
374
375void HidHost::HidHostGetReport(std::string device, uint8_t id, uint16_t size, uint8_t type)
376{
377    if (!IS_BT_ENABLED()) {
378        HILOGE("bluetooth is off.");
379        return;
380    }
381    sptr<IBluetoothHidHost> proxy = GetRemoteProxy<IBluetoothHidHost>(PROFILE_HID_HOST_SERVER);
382    CHECK_AND_RETURN_LOG(proxy != nullptr, "failed: no proxy");
383
384    return pimpl->HidHostGetReport(device, id, size, type);
385}
386} // namespace Bluetooth
387} // namespace OHOS