1/*
2 * Copyright (c) 2021-2023 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 <iostream>
16#include <sstream>
17#include <map>
18#include <string>
19#include <set>
20
21#include "usb_host_manager.h"
22#include "common_event_data.h"
23#include "common_event_manager.h"
24#include "common_event_support.h"
25#include "hilog_wrapper.h"
26#include "hisysevent.h"
27#include "cJSON.h"
28#include "usb_serial_reader.h"
29#include "usb_device.h"
30#include "usb_config.h"
31#include "usb_interface.h"
32#include "usb_errors.h"
33
34#ifdef USB_NOTIFICATION_ENABLE
35#include "usb_mass_storage_notification.h"
36#endif
37
38using namespace OHOS::AAFwk;
39using namespace OHOS::EventFwk;
40using namespace OHOS::HiviewDFX;
41
42namespace OHOS {
43namespace USB {
44constexpr int32_t CLASS_PRINT_LENGTH = 2;
45constexpr int32_t USAGE_IN_INTERFACE_CLASS = 0;
46constexpr uint8_t DES_USAGE_IN_INTERFACE = 0x02;
47std::map<int32_t, DeviceClassUsage> deviceUsageMap = {
48    {0x00, {DeviceClassUsage(2, "Use class information in the Interface Descriptors")}},
49    {0x01, {DeviceClassUsage(2, "Audio")}},
50    {0x02, {DeviceClassUsage(3, "Communications and CDC Control")}},
51    {0x03, {DeviceClassUsage(2, "HID(Human Interface Device)")}},
52    {0x05, {DeviceClassUsage(2, "Physical")}},
53    {0x06, {DeviceClassUsage(2, "Image")}},
54    {0x07, {DeviceClassUsage(2, "Printer")}},
55    {0x08, {DeviceClassUsage(2, "Mass Storage")}},
56    {0x09, {DeviceClassUsage(1, "Hub")}},
57    {0x0a, {DeviceClassUsage(2, "CDC-Data")}},
58    {0x0b, {DeviceClassUsage(2, "Smart Card")}},
59    {0x0d, {DeviceClassUsage(2, "Content Security")}},
60    {0x0e, {DeviceClassUsage(2, "Video")}},
61    {0x0f, {DeviceClassUsage(2, "Personal Healthcare")}},
62    {0x10, {DeviceClassUsage(2, "Audio/Video Device")}},
63    {0x11, {DeviceClassUsage(1, "Billboard Device Class")}},
64    {0x12, {DeviceClassUsage(2, "USB Type-C Bridge Class")}}
65};
66
67std::map<UsbDeviceType, std::string> interfaceUsageMap = {
68    {{UsbDeviceType(0x03, 0x01, 0x01, 0)}, "KeyBoard"},
69    {{UsbDeviceType(0x03, 0x01, 0x02, 0)}, "Mouse/Table/Touch screen"},
70};
71UsbHostManager::UsbHostManager(SystemAbility *systemAbility)
72{
73    systemAbility_ = systemAbility;
74}
75
76UsbHostManager::~UsbHostManager()
77{
78    for (auto &pair : devices_) {
79        delete pair.second;
80    }
81    devices_.clear();
82}
83
84void UsbHostManager::GetDevices(MAP_STR_DEVICE &devices)
85{
86    devices = devices_;
87}
88
89bool UsbHostManager::GetProductName(const std::string &deviceName, std::string &productName)
90{
91    auto iter = devices_.find(deviceName);
92    if (iter == devices_.end()) {
93        return false;
94    }
95
96    UsbDevice *dev = iter->second;
97    if (dev == nullptr) {
98        return false;
99    }
100
101    productName = dev->GetProductName();
102    return true;
103}
104
105bool UsbHostManager::DelDevice(uint8_t busNum, uint8_t devNum)
106{
107    std::string name = std::to_string(busNum) + "-" + std::to_string(devNum);
108    MAP_STR_DEVICE::iterator iter = devices_.find(name);
109    if (iter == devices_.end()) {
110        USB_HILOGF(MODULE_SERVICE, "name:%{public}s bus:%{public}hhu dev:%{public}hhu not exist", name.c_str(), busNum,
111            devNum);
112        return false;
113    }
114    USB_HILOGI(
115        MODULE_SERVICE, "device:%{public}s bus:%{public}hhu dev:%{public}hhu erase ", name.c_str(), busNum, devNum);
116    UsbDevice *devOld = iter->second;
117    if (devOld == nullptr) {
118        USB_HILOGE(MODULE_SERVICE, "invalid device");
119        return false;
120    }
121
122    auto isSuccess = PublishCommonEvent(CommonEventSupport::COMMON_EVENT_USB_DEVICE_DETACHED, *devOld);
123    if (!isSuccess) {
124        USB_HILOGW(MODULE_SERVICE, "send device attached broadcast failed");
125    }
126#ifdef USB_NOTIFICATION_ENABLE
127    UsbMassStorageNotification::GetInstance()->CancelNotification(devices_, *devOld, name);
128#endif
129
130    delete devOld;
131    devices_.erase(iter);
132    return true;
133}
134
135bool UsbHostManager::AddDevice(UsbDevice *dev)
136{
137    if (dev == nullptr) {
138        USB_HILOGF(MODULE_SERVICE, "device is NULL");
139        return false;
140    }
141
142    auto isSuccess = PublishCommonEvent(CommonEventSupport::COMMON_EVENT_USB_DEVICE_ATTACHED, *dev);
143    if (!isSuccess) {
144        USB_HILOGW(MODULE_SERVICE, "send device attached broadcast failed");
145    }
146
147    uint8_t busNum = dev->GetBusNum();
148    uint8_t devNum = dev->GetDevAddr();
149    std::string name = std::to_string(busNum) + "-" + std::to_string(devNum);
150    MAP_STR_DEVICE::iterator iter = devices_.find(name);
151    if (iter != devices_.end()) {
152        USB_HILOGF(MODULE_SERVICE, "device:%{public}s bus:%{public}hhu dev:%{public}hhu already exist", name.c_str(),
153            busNum, devNum);
154        UsbDevice *devOld = iter->second;
155        if (devOld != nullptr && devOld != dev) {
156            delete devOld;
157        }
158        devices_.erase(iter);
159    }
160    USB_HILOGI(
161        MODULE_SERVICE, "device:%{public}s bus:%{public}hhu dev:%{public}hhu insert", name.c_str(), busNum, devNum);
162    devices_.insert(std::pair<std::string, UsbDevice *>(name, dev));
163
164#ifdef USB_NOTIFICATION_ENABLE
165    UsbMassStorageNotification::GetInstance()->SendNotification(*dev);
166#endif
167    return true;
168}
169
170bool UsbHostManager::PublishCommonEvent(const std::string &event, const UsbDevice &dev)
171{
172    Want want;
173    want.SetAction(event);
174    CommonEventData data(want);
175    data.SetData(dev.getJsonString().c_str());
176    CommonEventPublishInfo publishInfo;
177    USB_HILOGI(MODULE_SERVICE, "send %{public}s broadcast device:%{public}s", event.c_str(),
178        dev.getJsonString().c_str());
179    ReportHostPlugSysEvent(event, dev);
180    return CommonEventManager::PublishCommonEvent(data, publishInfo);
181}
182
183bool UsbHostManager::Dump(int fd, const std::string &args)
184{
185    if (args.compare("-a") != 0) {
186        dprintf(fd, "args is not -a\n");
187        return false;
188    }
189
190    dprintf(fd, "Usb Host all device list info:\n");
191    for (const auto &item : devices_) {
192        dprintf(fd, "usb host list info: %s\n", item.second->getJsonString().c_str());
193    }
194    return true;
195}
196
197int32_t UsbHostManager::GetDeviceDescription(int32_t baseClass, std::string &description, uint8_t &usage)
198{
199    auto iter = deviceUsageMap.find(baseClass);
200    if (iter != deviceUsageMap.end()) {
201        description = iter->second.description;
202        usage = iter->second.usage;
203    } else {
204        description = "NA";
205        usage = 1;
206    }
207    return UEC_OK;
208}
209
210
211std::string UsbHostManager::ConcatenateToDescription(const UsbDeviceType &interfaceType, const std::string& str)
212{
213    std::stringstream ss;
214    ss << std::setw(CLASS_PRINT_LENGTH) << std::setfill('0') << std::hex << interfaceType.baseClass << "_";
215    ss << std::setw(CLASS_PRINT_LENGTH) << std::setfill('0') << std::hex << interfaceType.subClass << "_";
216    ss << std::setw(CLASS_PRINT_LENGTH) << std::setfill('0') << std::hex << interfaceType.protocol << ",";
217    ss << str;
218    return ss.str();
219}
220
221std::string UsbHostManager::GetInterfaceUsageDescription(const UsbDeviceType &interfaceType)
222{
223    std::string infUsageDes = "NA";
224    auto infUsageIter = interfaceUsageMap.find(interfaceType);
225    if (infUsageIter != interfaceUsageMap.end()) {
226        return infUsageIter->second;
227    }
228    return infUsageDes;
229}
230
231int32_t UsbHostManager::GetInterfaceDescription(const UsbDevice &dev, std::string &description, int32_t &baseClass)
232{
233    std::set<UsbDeviceType> useInterfaceType;
234    for (int32_t i = 0; i < dev.GetConfigCount(); i++) {
235        USBConfig config;
236        dev.GetConfig(i, config);
237        for (uint32_t j = 0; j < config.GetInterfaceCount(); j++) {
238            if (i != 0 || j != 0) {
239                description += ";";
240            }
241            UsbInterface interface;
242            config.GetInterface(j, interface);
243            baseClass = interface.GetClass();
244            UsbDeviceType interfaceType = {interface.GetClass(),
245                interface.GetSubClass(), interface.GetProtocol(), 0};
246                useInterfaceType.insert(interfaceType);
247                std::string infUsageDes = GetInterfaceUsageDescription(interfaceType);
248                description += ConcatenateToDescription(interfaceType, infUsageDes);
249        }
250    }
251    return UEC_OK;
252}
253
254void UsbHostManager::ReportHostPlugSysEvent(const std::string &event, const UsbDevice &dev)
255{
256    std::string deviceUsageDes;
257    uint8_t deviceUsage = 0;
258    GetDeviceDescription(dev.GetClass(), deviceUsageDes, deviceUsage);
259    std::string extUsageDes;
260    int32_t intfBaseClass = 0;
261    if (deviceUsage & DES_USAGE_IN_INTERFACE) {
262        GetInterfaceDescription(dev, extUsageDes, intfBaseClass);
263    }
264
265    if (dev.GetClass() == USAGE_IN_INTERFACE_CLASS) {
266        GetDeviceDescription(intfBaseClass, deviceUsageDes, deviceUsage);
267    }
268    USB_HILOGI(MODULE_SERVICE, "Host mode Indicates the insertion and removal information");
269    HiSysEventWrite(HiSysEvent::Domain::USB, "PLUG_IN_OUT_HOST_MODE", HiSysEvent::EventType::BEHAVIOR,
270        "DEVICE_NAME", dev.GetName(), "DEVICE_PROTOCOL", dev.GetProtocol(),
271        "DEVICE_SUBCLASS", dev.GetSubclass(), "DEVICE_CLASS", dev.GetClass(),
272        "DEVICE_CLASS_DESCRIPTION", deviceUsageDes, "INTERFACE_CLASS_DESCRIPTION", extUsageDes,
273        "VENDOR_ID", dev.GetVendorId(), "PRODUCT_ID", dev.GetProductId(),
274        "VERSION", dev.GetVersion(), "EVENT_NAME", event);
275}
276} // namespace USB
277} // namespace OHOS
278