* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <regex>
#include <unistd.h>
#include "hisysevent.h"
#include "usb_errors.h"
#include "usb_security_report.h"
#include "securec.h"
#include "serial_manager.h"
#include "hilog_wrapper.h"
#include "tokenid_kit.h"
#include "accesstoken_kit.h"
#define DUMP_PARAMS_NUM_2 2
using namespace OHOS::HiviewDFX;
using OHOS::USB::USB_MGR_LABEL;
using OHOS::USB::MODULE_USB_SERIAL;
using OHOS::USB::UEC_OK;
namespace OHOS {
namespace SERIAL {
constexpr int32_t PARAM_COUNT_ONE = 1;
constexpr int32_t ERR_CODE_IOEXCEPTION = -1;
constexpr int32_t ERR_CODE_DEVICENOTOPEN = -6;
constexpr int32_t ERR_CODE_TIMEOUT = -7;
constexpr int32_t ERR_CODE_ERROR_OVERFLOW = -8;
constexpr int32_t ERR_CODE_ERROR_DEVICE_BUSY = -16;
constexpr int32_t MAX_INPUT_STRING_NUMBER_SIZE = 9;
SerialManager::SerialManager()
{
if (serial_ == nullptr) {
serial_ = OHOS::HDI::Usb::Serial::V1_0::ISerialInterface::Get("serial_interface_service", true);
if (serial_ == nullptr) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: serial_ is nullptr", __func__);
}
}
usbRightManager_ = std::make_shared<USB::UsbRightManager>();
}
SerialManager::~SerialManager()
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
}
inline int32_t ErrorCodeWrap(int32_t errorCode)
{
if (errorCode == ERR_CODE_IOEXCEPTION || errorCode == ERR_CODE_ERROR_OVERFLOW) {
return USB::UEC_SERIAL_IO_EXCEPTION;
} else if (errorCode == ERR_CODE_DEVICENOTOPEN) {
return USB::UEC_SERIAL_DEVICENOTOPEN;
} else if (errorCode == ERR_CODE_TIMEOUT) {
return USB::UEC_INTERFACE_TIMED_OUT;
} else if (errorCode == ERR_CODE_ERROR_DEVICE_BUSY) {
return USB::UEC_SERIAL_PORT_REPEAT_OPEN;
} else {
return USB::UEC_SERIAL_OTHER_ERROR;
}
}
int32_t SerialManager::CheckPortAndTokenId(int32_t portId)
{
if (serial_ == nullptr) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: serial_ is nullptr", __func__);
return OHOS::USB::UEC_SERVICE_INVALID_VALUE;
}
if (!CheckTokenIdValidity(portId)) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: Application ID mismatch", __func__);
return OHOS::USB::UEC_SERIAL_PORT_NOT_OPEN;
}
return UEC_OK;
}
int32_t SerialManager::SerialOpen(int32_t portId)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
if (serial_ == nullptr) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: serial_ is nullptr", __func__);
return OHOS::USB::UEC_SERVICE_INVALID_VALUE;
}
std::lock_guard<std::mutex> guard(portTokenMapMutex_);
if (portTokenMap_.find(portId) != portTokenMap_.end()) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: The port has been opened", __func__);
return OHOS::USB::UEC_SERIAL_PORT_REPEAT_OPEN;
}
uint64_t timeMs = USB::UsbSecurityReport::GetCurrentTime();
int32_t ret = serial_->SerialOpen(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: SerialOpen failed ret = %{public}d", __func__, ret);
return ErrorCodeWrap(ret);
}
ReportSerialOperationSecurityInfo(portId, SERIAL_OPEN, timeMs);
portTokenMap_[portId] = IPCSkeleton::GetCallingTokenID();
return ret;
}
int32_t SerialManager::SerialClose(int32_t portId)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
int32_t ret = CheckPortAndTokenId(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: CheckPortAndTokenId failed", __func__);
return ret;
}
uint64_t timeMs = USB::UsbSecurityReport::GetCurrentTime();
ret = serial_->SerialClose(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: SerialClose failed ret = %{public}d", __func__, ret);
return ErrorCodeWrap(ret);
}
ReportSerialOperationSecurityInfo(portId, SERIAL_CLOSE, timeMs);
ResetFirstRead(portId);
ResetFirstWrite(portId);
std::lock_guard<std::mutex> guard(portTokenMapMutex_);
portTokenMap_.erase(portId);
return ret;
}
int32_t SerialManager::SerialRead(int32_t portId, std::vector<uint8_t> &data, uint32_t size,
uint32_t &actualSize, uint32_t timeout)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
int32_t ret = CheckPortAndTokenId(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: CheckPortAndTokenId failed", __func__);
return ret;
}
uint64_t timeMs = USB::UsbSecurityReport::GetCurrentTime();
ret = serial_->SerialRead(portId, data, size, timeout);
if (ret < UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: SerialRead failed ret = %{public}d", __func__, ret);
return ErrorCodeWrap(ret);
}
if (QueryAndRecordFirstRead(portId)) {
ReportSerialOperationSecurityInfo(portId, SERIAL_READ, timeMs);
}
actualSize = static_cast<uint32_t>(ret);
return UEC_OK;
}
int32_t SerialManager::SerialWrite(int32_t portId, const std::vector<uint8_t>& data, uint32_t size,
uint32_t &actualSize, uint32_t timeout)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
if (size > data.size()) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: size %{public}u is larger than data size %{public}zu",
__func__, size, data.size());
return OHOS::USB::UEC_SERVICE_INVALID_VALUE;
}
int32_t ret = CheckPortAndTokenId(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: CheckPortAndTokenId failed", __func__);
return ret;
}
uint64_t timeMs = USB::UsbSecurityReport::GetCurrentTime();
ret = serial_->SerialWrite(portId, data, size, timeout);
if (ret < UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: SerialWrite failed ret = %{public}d", __func__, ret);
return ErrorCodeWrap(ret);
}
if (QueryAndRecordFirstWrite(portId)) {
ReportSerialOperationSecurityInfo(portId, SERIAL_WRITE, timeMs);
}
actualSize = static_cast<uint32_t>(ret);
return UEC_OK;
}
int32_t SerialManager::SerialGetAttribute(int32_t portId, OHOS::HDI::Usb::Serial::V1_0::SerialAttribute& attribute)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
int32_t ret = CheckPortAndTokenId(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: CheckPortAndTokenId failed", __func__);
return ret;
}
ret = serial_->SerialGetAttribute(portId, attribute);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: SerialGetAttribute failed ret = %{public}d", __func__, ret);
return ErrorCodeWrap(ret);
}
return ret;
}
int32_t SerialManager::SerialSetAttribute(int32_t portId,
const OHOS::HDI::Usb::Serial::V1_0::SerialAttribute& attribute)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
int32_t ret = CheckPortAndTokenId(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: CheckPortAndTokenId failed", __func__);
return ret;
}
ret = serial_->SerialSetAttribute(portId, attribute);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: SerialSetAttribute failed ret = %{public}d", __func__, ret);
return ErrorCodeWrap(ret);
}
return ret;
}
int32_t SerialManager::SerialGetPortList(std::vector<OHOS::HDI::Usb::Serial::V1_0::SerialPort>& serialPortList)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
if (serial_ == nullptr) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: serial_ is nullptr", __func__);
return OHOS::USB::UEC_SERVICE_INVALID_VALUE;
}
int32_t ret = serial_->SerialGetPortList(serialPortList);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: SerialGetPortList failed ret = %{public}d", __func__, ret);
return ret;
}
UpdateSerialPortMap(serialPortList);
return ret;
}
void SerialManager::UpdateSerialPortMap(std::vector<OHOS::HDI::Usb::Serial::V1_0::SerialPort>& serialPortList)
{
std::lock_guard<std::mutex> guard(serialPortMapMutex_);
for (auto& it : serialPortList) {
serialPortMap_[it.portId] = it;
}
}
bool SerialManager::IsPortIdExist(int32_t portId)
{
std::lock_guard<std::mutex> guard(serialPortMapMutex_);
if (serialPortMap_.find(portId) == serialPortMap_.end()) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: port %{public}d not exist", __func__, portId);
return false;
}
return true;
}
bool SerialManager::CheckTokenIdValidity(int32_t portId)
{
std::lock_guard<std::mutex> guard(portTokenMapMutex_);
auto it = portTokenMap_.find(portId);
if (it == portTokenMap_.end()) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: The port is not open", __func__);
return false;
}
if (IPCSkeleton::GetCallingTokenID() != it->second) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: The tokenId corresponding to the port is incorrect", __func__);
return false;
}
return true;
}
void SerialManager::FreeTokenId(int32_t portId, uint32_t tokenId)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s: start", __func__);
std::lock_guard<std::mutex> guard(portTokenMapMutex_);
if ((portTokenMap_.find(portId) == portTokenMap_.end()) || (portTokenMap_[portId] != tokenId)) {
USB_HILOGE(MODULE_USB_SERIAL, "%{public}s: portid not exist or tokenId failed", __func__);
return;
}
if (serial_ != nullptr) {
serial_->SerialClose(portId);
}
portTokenMap_.erase(portId);
}
void SerialManager::SerialPortListDump(int32_t fd, const std::vector<std::string>& args)
{
if (args.size() != PARAM_COUNT_ONE) {
dprintf(fd, "port param error: exactly %d parameters are required\n", PARAM_COUNT_ONE);
ListGetDumpHelp(fd);
return;
}
if (args[0] == "-l") {
std::vector<OHOS::HDI::Usb::Serial::V1_0::SerialPort> serialPortList;
SerialGetPortList(serialPortList);
dprintf(fd, "=========== dump the serial port list ===========\n");
for (size_t i = 0; i < serialPortList.size(); ++i) {
char portName[20];
snprintf_s(portName, sizeof(portName), sizeof(portName)-1, "ttyUSB%zu", i);
dprintf(fd, "%s\n", portName);
}
dprintf(fd, "------------------------------------------------\n");
} else {
dprintf(fd, "port param error: invalid command '%s'\n", args[0].c_str());
ListGetDumpHelp(fd);
}
}
bool SerialManager::CheckDataAndProcessPortId(int32_t fd, const std::vector<std::string>& args,
OHOS::HDI::Usb::Serial::V1_0::SerialAttribute attribute)
{
if (!args.empty() && !std::regex_match(args[1], std::regex("^[0-9]+$"))) {
dprintf(fd, "Invalid input, please enter a valid integer\n");
return false;
}
if (args[1].size() > MAX_INPUT_STRING_NUMBER_SIZE) {
dprintf(fd, "Invalid input, value out of range\n");
return false;
}
int32_t portId = std::stoi(args[1]);
int32_t ret = SerialGetAttribute(portId, attribute);
if (ret != UEC_OK) {
ret = SerialOpen(portId);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "SerialOpen failed");
dprintf(fd, "Port %zu: port does not exist\n", portId);
return false;
}
ret = SerialGetAttribute(portId, attribute);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "SerialGetAttribute failed");
}
SerialClose(portId);
}
dprintf(fd, "Port %zu: baudrate: %zu stopBits:%zu parity:%zu dataBits:%zu\n",
portId, attribute.baudrate, attribute.stopBits, attribute.parity, attribute.dataBits);
return true;
}
void SerialManager::SerialGetAttributeDump(int32_t fd, const std::vector<std::string>& args)
{
size_t size = args.size();
OHOS::HDI::Usb::Serial::V1_0::SerialAttribute attribute;
if (size == 1) {
std::vector<OHOS::HDI::Usb::Serial::V1_0::SerialPort> serialPortList;
int32_t ret = SerialGetPortList(serialPortList);
if (ret != UEC_OK) {
USB_HILOGE(MODULE_USB_SERIAL, "SerialGetPortList failed");
return;
}
size_t portCount = serialPortList.size();
for (size_t i = 0; i < portCount; ++i) {
if (i > INT32_MAX) {
USB_HILOGE(MODULE_USB_SERIAL, "SerialGetPortList port index out of range");
break;
}
int32_t portId = static_cast<int32_t>(serialPortList[i].portId);
ret = SerialGetAttribute(portId, attribute);
if (ret != UEC_OK) {
SerialOpen(portId);
SerialGetAttribute(portId, attribute);
SerialClose(portId);
}
dprintf(fd, "Port %zu: baudrate: %zu stopBits:%zu parity:%zu dataBits:%zu\n",
i, attribute.baudrate, attribute.stopBits, attribute.parity, attribute.dataBits);
}
} else if (size == DUMP_PARAMS_NUM_2) {
if (!CheckDataAndProcessPortId(fd, args, attribute)) {
USB_HILOGE(MODULE_USB_SERIAL, "CheckDataAndProcessPortId failed");
return;
}
} else {
ListGetDumpHelp(fd);
}
}
void SerialManager::ListGetDumpHelp(int32_t fd)
{
dprintf(fd, "=========== dump the serial port information ===========\n");
dprintf(fd, "serail -l: Query All Serial Port List\n");
dprintf(fd, "serial -h: Serial port help\n");
dprintf(fd, "serial -g : Gets the properties of all ports\n");
dprintf(fd, "serial \"-g [port number]\": Gets the properties of the specified port\n");
dprintf(fd, "------------------------------------------------\n");
}
bool SerialManager::GetSerialPort(int32_t portId, OHOS::HDI::Usb::Serial::V1_0::SerialPort& serialPort)
{
std::lock_guard<std::mutex> guard(serialPortMapMutex_);
if (serialPortMap_.find(portId) == serialPortMap_.end()) {
USB_HILOGI(MODULE_USB_SERIAL, "serialPort not found");
return false;
}
serialPort = serialPortMap_[portId];
return true;
}
bool SerialManager::QueryAndRecordFirstRead(int32_t portId)
{
std::lock_guard lock(readStatusMutex_);
return portsHasBeenRead_.insert(portId).second;
}
bool SerialManager::QueryAndRecordFirstWrite(int32_t portId)
{
std::lock_guard lock(writeStatusMutex_);
return portsHasBeenWritten_.insert(portId).second;
}
void SerialManager::ResetFirstRead(int32_t portId)
{
std::lock_guard lock(readStatusMutex_);
portsHasBeenRead_.erase(portId);
}
void SerialManager::ResetFirstWrite(int32_t portId)
{
std::lock_guard lock(writeStatusMutex_);
portsHasBeenWritten_.erase(portId);
}
void SerialManager::ReportSerialOperationSecurityInfo(int32_t portId, std::string operationType, uint64_t time)
{
USB_HILOGI(MODULE_USB_SERIAL, "%{public}s enter: operation=%{public}s", __func__, operationType.c_str());
nlohmann::json operationJson {
{"happenTime", time},
{"portId", portId},
{"operationType", operationType},
{"uid", IPCSkeleton::GetCallingUid()},
};
USB::UsbSecurityReport::ReportSecurityInfo(USB_SERIAL_EVENT_ID, std::string(SERIAL_VERSION), operationJson);
}
}
}