设备监控
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/DeviceEvent.h.86CA2B2EF71C68E1.idx
Normal file
BIN
.cache/clangd/index/DeviceEvent.h.86CA2B2EF71C68E1.idx
Normal file
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/DeviceMonitorService.h.2C037D82AC481AAB.idx
Normal file
BIN
.cache/clangd/index/DeviceMonitorService.h.2C037D82AC481AAB.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/IDeviceMonitor.h.35FD4D7CC78F8E5E.idx
Normal file
BIN
.cache/clangd/index/IDeviceMonitor.h.35FD4D7CC78F8E5E.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/IDeviceRegistry.h.255744FF99F84B26.idx
Normal file
BIN
.cache/clangd/index/IDeviceRegistry.h.255744FF99F84B26.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/NetlinkDeviceMonitor.h.D31493ABAC6FE7FD.idx
Normal file
BIN
.cache/clangd/index/NetlinkDeviceMonitor.h.D31493ABAC6FE7FD.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/UdevDeviceMonitor.cpp.8FD4DE713A589E66.idx
Normal file
BIN
.cache/clangd/index/UdevDeviceMonitor.cpp.8FD4DE713A589E66.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/UdevDeviceMonitor.h.0028E083196B240B.idx
Normal file
BIN
.cache/clangd/index/UdevDeviceMonitor.h.0028E083196B240B.idx
Normal file
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/WindowsDeviceMonitor.h.00AD1ABB43F51CCC.idx
Normal file
BIN
.cache/clangd/index/WindowsDeviceMonitor.h.00AD1ABB43F51CCC.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -31,6 +31,7 @@ set(CMAKE_AUTORCC ON)
|
|||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
# 查找Qt6(守护进程只需要 Core/DBus/Network/SerialPort/Sql)
|
# 查找Qt6(守护进程只需要 Core/DBus/Network/SerialPort/Sql)
|
||||||
find_package(Qt6 6.5 REQUIRED COMPONENTS Core SerialPort Network Sql DBus)
|
find_package(Qt6 6.5 REQUIRED COMPONENTS Core SerialPort Network Sql DBus)
|
||||||
|
include(CheckIncludeFileCXX)
|
||||||
|
|
||||||
# 检测编译平台
|
# 检测编译平台
|
||||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
|
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
|
||||||
@@ -77,8 +78,19 @@ qt_add_executable(softbus_daemon
|
|||||||
# device bus: tree & capabilities
|
# device bus: tree & capabilities
|
||||||
src/device_bus/tree/DeviceTreeModel.h
|
src/device_bus/tree/DeviceTreeModel.h
|
||||||
src/device_bus/tree/DeviceTreeModel.cpp
|
src/device_bus/tree/DeviceTreeModel.cpp
|
||||||
src/device_bus/capabilities/DriverCapabilityProvider.h
|
|
||||||
src/device_bus/capabilities/DriverCapabilityProvider.cpp
|
# device bus: monitor
|
||||||
|
src/device_bus/monitor/DeviceEvent.h
|
||||||
|
src/device_bus/monitor/IDeviceMonitor.h
|
||||||
|
src/device_bus/monitor/DeviceMonitorService.h
|
||||||
|
src/device_bus/monitor/DeviceMonitorService.cpp
|
||||||
|
src/device_bus/monitor/UdevDeviceMonitor.h
|
||||||
|
src/device_bus/monitor/UdevDeviceMonitor.cpp
|
||||||
|
src/device_bus/monitor/NetlinkDeviceMonitor.h
|
||||||
|
src/device_bus/monitor/NetlinkDeviceMonitor.cpp
|
||||||
|
src/device_bus/monitor/WindowsDeviceMonitor.h
|
||||||
|
src/device_bus/monitor/WindowsDeviceMonitor.cpp
|
||||||
|
|
||||||
|
|
||||||
# device bus: facade & manager
|
# device bus: facade & manager
|
||||||
src/device_bus/DeviceBus.h
|
src/device_bus/DeviceBus.h
|
||||||
@@ -114,6 +126,27 @@ target_link_libraries(softbus_daemon
|
|||||||
Qt6::Network
|
Qt6::Network
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Platform-specific deps
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if(PkgConfig_FOUND)
|
||||||
|
pkg_check_modules(UDEV QUIET libudev)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(UDEV_FOUND)
|
||||||
|
target_include_directories(softbus_daemon PRIVATE ${UDEV_INCLUDE_DIRS})
|
||||||
|
target_link_directories(softbus_daemon PRIVATE ${UDEV_LIBRARY_DIRS})
|
||||||
|
target_link_libraries(softbus_daemon PRIVATE ${UDEV_LIBRARIES})
|
||||||
|
else()
|
||||||
|
# Fallback: rely on system linker search path
|
||||||
|
target_link_libraries(softbus_daemon PRIVATE udev)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(softbus_daemon PRIVATE setupapi iphlpapi user32 advapi32)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(plugins)
|
add_subdirectory(plugins)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -6,6 +6,7 @@
|
|||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
|
|
||||||
#include "device_bus/manager/DeviceBusManager.h"
|
#include "device_bus/manager/DeviceBusManager.h"
|
||||||
|
#include "device_bus/monitor/DeviceMonitorService.h"
|
||||||
#include "device_bus/tree/DeviceTreeModel.h"
|
#include "device_bus/tree/DeviceTreeModel.h"
|
||||||
#include "utils/logs/logging.h"
|
#include "utils/logs/logging.h"
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ namespace softbus::device_bus {
|
|||||||
class DeviceBus::Impl {
|
class DeviceBus::Impl {
|
||||||
public:
|
public:
|
||||||
DeviceBusManager manager;
|
DeviceBusManager manager;
|
||||||
|
std::unique_ptr<monitor::DeviceMonitorService> monitorService;
|
||||||
std::shared_ptr<DeviceTreeModel> treeModel;
|
std::shared_ptr<DeviceTreeModel> treeModel;
|
||||||
QString configPath;
|
QString configPath;
|
||||||
bool deviceTreeDirty{false};
|
bool deviceTreeDirty{false};
|
||||||
@@ -32,6 +34,13 @@ DeviceBus::~DeviceBus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceBus::initialize(const QJsonObject &rootConfig) {
|
bool DeviceBus::initialize(const QJsonObject &rootConfig) {
|
||||||
|
if (!d->monitorService) {
|
||||||
|
d->monitorService = std::make_unique<monitor::DeviceMonitorService>(nullptr);
|
||||||
|
if (!d->monitorService->start()) {
|
||||||
|
LOG_WARNING() << "DeviceBus: device monitor service start failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!d->treeModel) {
|
if (!d->treeModel) {
|
||||||
d->treeModel = std::make_shared<DeviceTreeModel>();
|
d->treeModel = std::make_shared<DeviceTreeModel>();
|
||||||
}
|
}
|
||||||
@@ -40,6 +49,11 @@ bool DeviceBus::initialize(const QJsonObject &rootConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceBus::shutdown() {
|
void DeviceBus::shutdown() {
|
||||||
|
if (d->monitorService) {
|
||||||
|
d->monitorService->stop();
|
||||||
|
d->monitorService.reset();
|
||||||
|
}
|
||||||
|
|
||||||
d->manager.shutdown();
|
d->manager.shutdown();
|
||||||
|
|
||||||
if (!d->deviceTreeDirty) {
|
if (!d->deviceTreeDirty) {
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
#include "device_bus/capabilities/DriverCapabilityProvider.h"
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonArray>
|
|
||||||
|
|
||||||
#include "utils/logs/logging.h"
|
|
||||||
|
|
||||||
bool DriverCapabilityProvider::loadFromFile(const QString& jsonPath, QString* errorMessage)
|
|
||||||
{
|
|
||||||
m_defaults = QJsonObject();
|
|
||||||
m_enums = QJsonObject();
|
|
||||||
|
|
||||||
QFile f(jsonPath);
|
|
||||||
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
||||||
if (errorMessage) {
|
|
||||||
*errorMessage = QStringLiteral("Failed to open capability file: %1").arg(jsonPath);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray data = f.readAll();
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
QJsonParseError pe;
|
|
||||||
const QJsonDocument doc = QJsonDocument::fromJson(data, &pe);
|
|
||||||
if (pe.error != QJsonParseError::NoError || !doc.isObject()) {
|
|
||||||
if (errorMessage) {
|
|
||||||
*errorMessage = QStringLiteral("Invalid JSON in capability file %1: %2")
|
|
||||||
.arg(jsonPath, pe.errorString());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QJsonObject root = doc.object();
|
|
||||||
m_defaults = root.value(QStringLiteral("defaults")).toObject();
|
|
||||||
m_enums = root.value(QStringLiteral("enums")).toObject();
|
|
||||||
|
|
||||||
LOG_INFO() << "DriverCapabilityProvider loaded from" << jsonPath;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject DriverCapabilityProvider::mergeAndValidateParams(const QJsonObject& nodeParams) const
|
|
||||||
{
|
|
||||||
// 1. 从 defaults 拷贝一份出来
|
|
||||||
QJsonObject result = m_defaults;
|
|
||||||
|
|
||||||
// 2. 覆盖节点里的显式参数
|
|
||||||
for (auto it = nodeParams.constBegin(); it != nodeParams.constEnd(); ++it) {
|
|
||||||
const QString key = it.key();
|
|
||||||
const QJsonValue value = it.value();
|
|
||||||
|
|
||||||
// 如果存在枚举限制,则先校验
|
|
||||||
const QJsonValue enumVal = m_enums.value(key);
|
|
||||||
if (enumVal.isArray()) {
|
|
||||||
const QJsonArray arr = enumVal.toArray();
|
|
||||||
bool ok = false;
|
|
||||||
for (const QJsonValue& candidate : arr) {
|
|
||||||
if (candidate == value) {
|
|
||||||
ok = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
LOG_WARNING() << "DriverCapabilityProvider: param" << key
|
|
||||||
<< "value" << value.toVariant()
|
|
||||||
<< "not in allowed enum, keep default";
|
|
||||||
continue; // 不覆盖默认值
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.insert(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
// 负责加载 drivers 下的 parameters.json,并对节点 params 做默认值合并与简单枚举校验
|
|
||||||
|
|
||||||
class DriverCapabilityProvider
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// 从给定路径加载能力描述(如 "src/hardware/drivers/serial/parameters.json")
|
|
||||||
bool loadFromFile(const QString& jsonPath, QString* errorMessage = nullptr);
|
|
||||||
|
|
||||||
// 将节点 params 与 defaults 合并,并按 enums 做简单校验
|
|
||||||
QJsonObject mergeAndValidateParams(const QJsonObject& nodeParams) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QJsonObject m_defaults;
|
|
||||||
QJsonObject m_enums;
|
|
||||||
};
|
|
||||||
|
|
||||||
74
src/device_bus/monitor/DeviceEvent.h
Normal file
74
src/device_bus/monitor/DeviceEvent.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class DeviceEventType {
|
||||||
|
Serial,
|
||||||
|
Usb,
|
||||||
|
Storage,
|
||||||
|
NetInterface,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DeviceEventAction {
|
||||||
|
Add,
|
||||||
|
Remove,
|
||||||
|
Change,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeviceEvent
|
||||||
|
{
|
||||||
|
DeviceEventType type{DeviceEventType::Unknown};
|
||||||
|
DeviceEventAction action{DeviceEventAction::Unknown};
|
||||||
|
QDateTime timestamp{QDateTime::currentDateTimeUtc()};
|
||||||
|
|
||||||
|
// Common identifiers
|
||||||
|
QString subsystem; // e.g. "tty", "usb", "block", "net"
|
||||||
|
QString devnode; // e.g. /dev/ttyUSB0
|
||||||
|
QString devicePath; // platform-native path (Windows device interface path)
|
||||||
|
|
||||||
|
// USB-ish fields
|
||||||
|
QString vid;
|
||||||
|
QString pid;
|
||||||
|
QString serial;
|
||||||
|
QString model;
|
||||||
|
QString vendor;
|
||||||
|
|
||||||
|
// Network fields
|
||||||
|
QString ifname;
|
||||||
|
int ifindex{-1};
|
||||||
|
bool linkUp{false};
|
||||||
|
|
||||||
|
// Extra properties (best-effort)
|
||||||
|
QMap<QString, QString> props;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline QString toString(DeviceEventType t)
|
||||||
|
{
|
||||||
|
switch (t) {
|
||||||
|
case DeviceEventType::Serial: return QStringLiteral("Serial");
|
||||||
|
case DeviceEventType::Usb: return QStringLiteral("Usb");
|
||||||
|
case DeviceEventType::Storage: return QStringLiteral("Storage");
|
||||||
|
case DeviceEventType::NetInterface: return QStringLiteral("NetInterface");
|
||||||
|
default: return QStringLiteral("Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString toString(DeviceEventAction a)
|
||||||
|
{
|
||||||
|
switch (a) {
|
||||||
|
case DeviceEventAction::Add: return QStringLiteral("add");
|
||||||
|
case DeviceEventAction::Remove: return QStringLiteral("remove");
|
||||||
|
case DeviceEventAction::Change: return QStringLiteral("change");
|
||||||
|
default: return QStringLiteral("unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
97
src/device_bus/monitor/DeviceMonitorService.cpp
Normal file
97
src/device_bus/monitor/DeviceMonitorService.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include "device_bus/monitor/DeviceMonitorService.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
#include "utils/logs/logging.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include "device_bus/monitor/UdevDeviceMonitor.h"
|
||||||
|
#include "device_bus/monitor/NetlinkDeviceMonitor.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include "device_bus/monitor/WindowsDeviceMonitor.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
DeviceMonitorService::DeviceMonitorService(QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
m_monitors.emplace_back(std::make_unique<UdevDeviceMonitor>(this));
|
||||||
|
m_monitors.emplace_back(std::make_unique<NetlinkDeviceMonitor>(this));
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
m_monitors.emplace_back(std::make_unique<WindowsDeviceMonitor>(this));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (auto& m : m_monitors) {
|
||||||
|
m->setCallback([this](const DeviceEvent& ev) { onEvent(ev); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceMonitorService::~DeviceMonitorService()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceMonitorService::start()
|
||||||
|
{
|
||||||
|
if (m_started) return true;
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
|
for (auto& m : m_monitors) {
|
||||||
|
ok = m->start() && ok;
|
||||||
|
}
|
||||||
|
m_started = ok;
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceMonitorService::stop()
|
||||||
|
{
|
||||||
|
if (!m_started) return;
|
||||||
|
for (auto& m : m_monitors) {
|
||||||
|
m->stop();
|
||||||
|
}
|
||||||
|
m_started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceMonitorService::onEvent(const DeviceEvent& ev)
|
||||||
|
{
|
||||||
|
// De-dup (short window): suppress identical events bursts
|
||||||
|
const QString key = QStringLiteral("%1|%2|%3|%4|%5|%6|%7|%8|%9")
|
||||||
|
.arg(toString(ev.type),
|
||||||
|
toString(ev.action),
|
||||||
|
ev.subsystem,
|
||||||
|
ev.devnode,
|
||||||
|
ev.props.value(QStringLiteral("SYSPATH")),
|
||||||
|
ev.ifname,
|
||||||
|
QString::number(ev.ifindex),
|
||||||
|
ev.vid + ev.pid,
|
||||||
|
ev.serial);
|
||||||
|
|
||||||
|
const qint64 nowMs = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
const qint64 lastMs = m_lastEventMsByKey.value(key, -1);
|
||||||
|
if (lastMs >= 0 && (nowMs - lastMs) < 800) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_lastEventMsByKey.insert(key, nowMs);
|
||||||
|
|
||||||
|
// 第一版:仅日志
|
||||||
|
LOG_INFO() << "DeviceMonitor event"
|
||||||
|
<< "type=" << toString(ev.type)
|
||||||
|
<< "action=" << toString(ev.action)
|
||||||
|
<< "subsystem=" << ev.subsystem
|
||||||
|
<< "devnode=" << ev.devnode
|
||||||
|
<< "ifname=" << ev.ifname
|
||||||
|
<< "ifindex=" << ev.ifindex
|
||||||
|
<< "linkUp=" << ev.linkUp
|
||||||
|
<< "vid=" << ev.vid
|
||||||
|
<< "pid=" << ev.pid
|
||||||
|
<< "serial=" << ev.serial
|
||||||
|
<< "path=" << ev.devicePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
36
src/device_bus/monitor/DeviceMonitorService.h
Normal file
36
src/device_bus/monitor/DeviceMonitorService.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "device_bus/monitor/IDeviceMonitor.h"
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
class DeviceMonitorService : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DeviceMonitorService(QObject* parent = nullptr);
|
||||||
|
~DeviceMonitorService() override;
|
||||||
|
|
||||||
|
bool start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onEvent(const DeviceEvent& ev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<IDeviceMonitor>> m_monitors;
|
||||||
|
bool m_started{false};
|
||||||
|
|
||||||
|
// Lightweight de-dup: key -> last timestamp (ms)
|
||||||
|
QHash<QString, qint64> m_lastEventMsByKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
41
src/device_bus/monitor/IDeviceMonitor.h
Normal file
41
src/device_bus/monitor/IDeviceMonitor.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "device_bus/monitor/DeviceEvent.h"
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
class IDeviceMonitor : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
using EventCallback = std::function<void(const DeviceEvent&)>;
|
||||||
|
|
||||||
|
explicit IDeviceMonitor(QObject* parent = nullptr) : QObject(parent) {}
|
||||||
|
~IDeviceMonitor() override = default;
|
||||||
|
|
||||||
|
virtual bool start() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
void setCallback(EventCallback cb) { m_cb = std::move(cb); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void emitEvent(const DeviceEvent& ev)
|
||||||
|
{
|
||||||
|
if (m_cb) m_cb(ev);
|
||||||
|
emit event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void event(const softbus::device_bus::monitor::DeviceEvent& ev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
EventCallback m_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
155
src/device_bus/monitor/NetlinkDeviceMonitor.cpp
Normal file
155
src/device_bus/monitor/NetlinkDeviceMonitor.cpp
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#include "device_bus/monitor/NetlinkDeviceMonitor.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#include "utils/logs/logging.h"
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
NetlinkDeviceMonitor::NetlinkDeviceMonitor(QObject* parent)
|
||||||
|
: IDeviceMonitor(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NetlinkDeviceMonitor::~NetlinkDeviceMonitor()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetlinkDeviceMonitor::start()
|
||||||
|
{
|
||||||
|
if (m_sock >= 0) return true;
|
||||||
|
|
||||||
|
m_sock = ::socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||||
|
if (m_sock < 0) {
|
||||||
|
LOG_ERROR() << "NetlinkDeviceMonitor: socket failed errno=" << errno;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_nl addr{};
|
||||||
|
addr.nl_family = AF_NETLINK;
|
||||||
|
addr.nl_groups = RTMGRP_LINK;
|
||||||
|
if (::bind(m_sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
|
||||||
|
LOG_ERROR() << "NetlinkDeviceMonitor: bind failed errno=" << errno;
|
||||||
|
stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_notifier = new QSocketNotifier(m_sock, QSocketNotifier::Read, this);
|
||||||
|
connect(m_notifier, &QSocketNotifier::activated, this, [this]() { onReadable(); });
|
||||||
|
|
||||||
|
LOG_INFO() << "NetlinkDeviceMonitor started sock=" << m_sock;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetlinkDeviceMonitor::stop()
|
||||||
|
{
|
||||||
|
if (m_notifier) {
|
||||||
|
m_notifier->setEnabled(false);
|
||||||
|
m_notifier->deleteLater();
|
||||||
|
m_notifier = nullptr;
|
||||||
|
}
|
||||||
|
if (m_sock >= 0) {
|
||||||
|
::close(m_sock);
|
||||||
|
m_sock = -1;
|
||||||
|
}
|
||||||
|
m_seenIfIndex.clear();
|
||||||
|
m_lastIfNameByIndex.clear();
|
||||||
|
m_lastLinkUpByIndex.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetlinkDeviceMonitor::onReadable()
|
||||||
|
{
|
||||||
|
if (m_sock < 0) return;
|
||||||
|
|
||||||
|
alignas(nlmsghdr) char buf[8192];
|
||||||
|
const ssize_t len = ::recv(m_sock, buf, sizeof(buf), 0);
|
||||||
|
if (len <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int remaining = static_cast<int>(len);
|
||||||
|
for (nlmsghdr* nh = reinterpret_cast<nlmsghdr*>(buf);
|
||||||
|
NLMSG_OK(nh, static_cast<unsigned int>(remaining));
|
||||||
|
nh = NLMSG_NEXT(nh, remaining)) {
|
||||||
|
|
||||||
|
if (nh->nlmsg_type == NLMSG_DONE || nh->nlmsg_type == NLMSG_ERROR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nh->nlmsg_type != RTM_NEWLINK && nh->nlmsg_type != RTM_DELLINK) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(nh));
|
||||||
|
const int ifindex = ifi ? ifi->ifi_index : -1;
|
||||||
|
|
||||||
|
QString ifname;
|
||||||
|
bool linkUp = false;
|
||||||
|
|
||||||
|
// Parse attributes
|
||||||
|
int attrLen = static_cast<int>(nh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
|
||||||
|
for (rtattr* rta = IFLA_RTA(ifi); RTA_OK(rta, attrLen); rta = RTA_NEXT(rta, attrLen)) {
|
||||||
|
if (rta->rta_type == IFLA_IFNAME) {
|
||||||
|
ifname = QString::fromUtf8(reinterpret_cast<const char*>(RTA_DATA(rta)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link state (best-effort)
|
||||||
|
if (ifi) {
|
||||||
|
linkUp = (ifi->ifi_flags & IFF_RUNNING) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceEvent ev;
|
||||||
|
ev.timestamp = QDateTime::currentDateTimeUtc();
|
||||||
|
ev.type = DeviceEventType::NetInterface;
|
||||||
|
ev.subsystem = QStringLiteral("net");
|
||||||
|
ev.ifindex = ifindex;
|
||||||
|
ev.ifname = ifname;
|
||||||
|
ev.linkUp = linkUp;
|
||||||
|
|
||||||
|
if (nh->nlmsg_type == RTM_DELLINK) {
|
||||||
|
ev.action = DeviceEventAction::Remove;
|
||||||
|
m_seenIfIndex.remove(ifindex);
|
||||||
|
m_lastIfNameByIndex.remove(ifindex);
|
||||||
|
m_lastLinkUpByIndex.remove(ifindex);
|
||||||
|
} else {
|
||||||
|
// NEWLINK can be add or change; treat first time as add
|
||||||
|
if (!m_seenIfIndex.contains(ifindex)) {
|
||||||
|
ev.action = DeviceEventAction::Add;
|
||||||
|
m_seenIfIndex.insert(ifindex);
|
||||||
|
m_lastIfNameByIndex.insert(ifindex, ifname);
|
||||||
|
m_lastLinkUpByIndex.insert(ifindex, linkUp);
|
||||||
|
} else {
|
||||||
|
const QString lastName = m_lastIfNameByIndex.value(ifindex);
|
||||||
|
const bool lastLink = m_lastLinkUpByIndex.value(ifindex, linkUp);
|
||||||
|
|
||||||
|
// Drop pure spam: only emit change if name or link state changes
|
||||||
|
if (lastName == ifname && lastLink == linkUp) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev.action = DeviceEventAction::Change;
|
||||||
|
m_lastIfNameByIndex.insert(ifindex, ifname);
|
||||||
|
m_lastLinkUpByIndex.insert(ifindex, linkUp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
38
src/device_bus/monitor/NetlinkDeviceMonitor.h
Normal file
38
src/device_bus/monitor/NetlinkDeviceMonitor.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "device_bus/monitor/IDeviceMonitor.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
class NetlinkDeviceMonitor : public IDeviceMonitor
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit NetlinkDeviceMonitor(QObject* parent = nullptr);
|
||||||
|
~NetlinkDeviceMonitor() override;
|
||||||
|
|
||||||
|
bool start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onReadable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_sock{-1};
|
||||||
|
QSocketNotifier* m_notifier{nullptr};
|
||||||
|
QSet<int> m_seenIfIndex;
|
||||||
|
QHash<int, QString> m_lastIfNameByIndex;
|
||||||
|
QHash<int, bool> m_lastLinkUpByIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
222
src/device_bus/monitor/UdevDeviceMonitor.cpp
Normal file
222
src/device_bus/monitor/UdevDeviceMonitor.cpp
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
#include "device_bus/monitor/UdevDeviceMonitor.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#include "utils/logs/logging.h"
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
UdevDeviceMonitor::UdevDeviceMonitor(QObject* parent)
|
||||||
|
: IDeviceMonitor(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UdevDeviceMonitor::~UdevDeviceMonitor()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UdevDeviceMonitor::start()
|
||||||
|
{
|
||||||
|
if (m_mon) return true;
|
||||||
|
|
||||||
|
m_udev = udev_new();
|
||||||
|
if (!m_udev) {
|
||||||
|
LOG_ERROR() << "UdevDeviceMonitor: udev_new failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mon = udev_monitor_new_from_netlink(m_udev, "udev");
|
||||||
|
if (!m_mon) {
|
||||||
|
LOG_ERROR() << "UdevDeviceMonitor: udev_monitor_new_from_netlink failed";
|
||||||
|
udev_unref(m_udev);
|
||||||
|
m_udev = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter subsystems
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(m_mon, "tty", nullptr);
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(m_mon, "usb", nullptr);
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype(m_mon, "block", nullptr);
|
||||||
|
|
||||||
|
if (udev_monitor_enable_receiving(m_mon) != 0) {
|
||||||
|
LOG_ERROR() << "UdevDeviceMonitor: enable_receiving failed";
|
||||||
|
stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fd = udev_monitor_get_fd(m_mon);
|
||||||
|
if (m_fd < 0) {
|
||||||
|
LOG_ERROR() << "UdevDeviceMonitor: monitor fd invalid";
|
||||||
|
stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
|
||||||
|
connect(m_notifier, &QSocketNotifier::activated, this, [this]() { onReadable(); });
|
||||||
|
|
||||||
|
LOG_INFO() << "UdevDeviceMonitor started fd=" << m_fd;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdevDeviceMonitor::stop()
|
||||||
|
{
|
||||||
|
if (m_notifier) {
|
||||||
|
m_notifier->setEnabled(false);
|
||||||
|
m_notifier->deleteLater();
|
||||||
|
m_notifier = nullptr;
|
||||||
|
}
|
||||||
|
m_fd = -1;
|
||||||
|
|
||||||
|
if (m_mon) {
|
||||||
|
udev_monitor_unref(m_mon);
|
||||||
|
m_mon = nullptr;
|
||||||
|
}
|
||||||
|
if (m_udev) {
|
||||||
|
udev_unref(m_udev);
|
||||||
|
m_udev = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UdevDeviceMonitor::onReadable()
|
||||||
|
{
|
||||||
|
if (!m_mon) return;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
struct udev_device* dev = udev_monitor_receive_device(m_mon);
|
||||||
|
if (!dev) break;
|
||||||
|
|
||||||
|
const char* action = udev_device_get_action(dev);
|
||||||
|
DeviceEvent ev = toEvent(dev, action);
|
||||||
|
|
||||||
|
// Drop unknown action (usually noise / incomplete events)
|
||||||
|
if (ev.action == DeviceEventAction::Unknown) {
|
||||||
|
udev_device_unref(dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// USB: only keep usb_device (drop interface-level noise)
|
||||||
|
if (ev.subsystem == QStringLiteral("usb")) {
|
||||||
|
const QString devtype = ev.props.value(QStringLiteral("DEVTYPE"));
|
||||||
|
if (!devtype.isEmpty() && devtype != QStringLiteral("usb_device")) {
|
||||||
|
udev_device_unref(dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop most "change" spam for usb (keep add/remove)
|
||||||
|
if (ev.action == DeviceEventAction::Change) {
|
||||||
|
udev_device_unref(dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it carries no stable identifiers, it's not useful
|
||||||
|
if (ev.devnode.isEmpty() && ev.vid.isEmpty() && ev.pid.isEmpty() && ev.serial.isEmpty()) {
|
||||||
|
udev_device_unref(dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage: keep add/remove; drop change spam
|
||||||
|
if (ev.type == DeviceEventType::Storage && ev.action == DeviceEventAction::Change) {
|
||||||
|
udev_device_unref(dev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitEvent(ev);
|
||||||
|
udev_device_unref(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString UdevDeviceMonitor::getProp(struct udev_device* dev, const char* key)
|
||||||
|
{
|
||||||
|
if (!dev || !key) return {};
|
||||||
|
const char* v = udev_device_get_property_value(dev, key);
|
||||||
|
return v ? QString::fromUtf8(v) : QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceEvent UdevDeviceMonitor::toEvent(struct udev_device* dev, const char* action)
|
||||||
|
{
|
||||||
|
DeviceEvent ev;
|
||||||
|
ev.timestamp = QDateTime::currentDateTimeUtc();
|
||||||
|
|
||||||
|
const char* subsys = udev_device_get_subsystem(dev);
|
||||||
|
if (subsys) ev.subsystem = QString::fromUtf8(subsys);
|
||||||
|
|
||||||
|
const char* devtype = udev_device_get_devtype(dev);
|
||||||
|
if (devtype) ev.props.insert(QStringLiteral("DEVTYPE"), QString::fromUtf8(devtype));
|
||||||
|
|
||||||
|
const char* syspath = udev_device_get_syspath(dev);
|
||||||
|
if (syspath) ev.props.insert(QStringLiteral("SYSPATH"), QString::fromUtf8(syspath));
|
||||||
|
|
||||||
|
const char* devnode = udev_device_get_devnode(dev);
|
||||||
|
if (devnode) ev.devnode = QString::fromUtf8(devnode);
|
||||||
|
|
||||||
|
const QString act = action ? QString::fromUtf8(action) : QString();
|
||||||
|
if (act == QStringLiteral("add")) ev.action = DeviceEventAction::Add;
|
||||||
|
else if (act == QStringLiteral("remove")) ev.action = DeviceEventAction::Remove;
|
||||||
|
else if (act == QStringLiteral("change")) ev.action = DeviceEventAction::Change;
|
||||||
|
else ev.action = DeviceEventAction::Unknown;
|
||||||
|
|
||||||
|
if (ev.subsystem == QStringLiteral("tty")) {
|
||||||
|
ev.type = DeviceEventType::Serial;
|
||||||
|
// devnode like /dev/ttyUSB0
|
||||||
|
} else if (ev.subsystem == QStringLiteral("usb")) {
|
||||||
|
ev.type = DeviceEventType::Usb;
|
||||||
|
} else if (ev.subsystem == QStringLiteral("block")) {
|
||||||
|
// Prefer only usb-backed block devices
|
||||||
|
const QString idBus = getProp(dev, "ID_BUS");
|
||||||
|
if (idBus == QStringLiteral("usb")) {
|
||||||
|
ev.type = DeviceEventType::Storage;
|
||||||
|
} else {
|
||||||
|
// check parent chain for usb
|
||||||
|
struct udev_device* p = udev_device_get_parent_with_subsystem_devtype(dev, "usb", nullptr);
|
||||||
|
if (p) {
|
||||||
|
ev.type = DeviceEventType::Storage;
|
||||||
|
} else {
|
||||||
|
ev.type = DeviceEventType::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ev.type = DeviceEventType::Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common USB-ish props (best-effort)
|
||||||
|
ev.vid = getProp(dev, "ID_VENDOR_ID");
|
||||||
|
ev.pid = getProp(dev, "ID_MODEL_ID");
|
||||||
|
ev.serial = getProp(dev, "ID_SERIAL_SHORT");
|
||||||
|
ev.model = getProp(dev, "ID_MODEL");
|
||||||
|
ev.vendor = getProp(dev, "ID_VENDOR");
|
||||||
|
|
||||||
|
// Fallback to sysfs attributes for usb subsystem
|
||||||
|
if (ev.vid.isEmpty() && ev.subsystem == QStringLiteral("usb")) {
|
||||||
|
const char* a = udev_device_get_sysattr_value(dev, "idVendor");
|
||||||
|
if (a) ev.vid = QString::fromUtf8(a);
|
||||||
|
}
|
||||||
|
if (ev.pid.isEmpty() && ev.subsystem == QStringLiteral("usb")) {
|
||||||
|
const char* a = udev_device_get_sysattr_value(dev, "idProduct");
|
||||||
|
if (a) ev.pid = QString::fromUtf8(a);
|
||||||
|
}
|
||||||
|
if (ev.serial.isEmpty() && ev.subsystem == QStringLiteral("usb")) {
|
||||||
|
const char* a = udev_device_get_sysattr_value(dev, "serial");
|
||||||
|
if (a) ev.serial = QString::fromUtf8(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ev.devnode.isEmpty()) {
|
||||||
|
ev.props.insert(QStringLiteral("DEVNAME"), ev.devnode);
|
||||||
|
}
|
||||||
|
if (!ev.subsystem.isEmpty()) {
|
||||||
|
ev.props.insert(QStringLiteral("SUBSYSTEM"), ev.subsystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ev;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
39
src/device_bus/monitor/UdevDeviceMonitor.h
Normal file
39
src/device_bus/monitor/UdevDeviceMonitor.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "device_bus/monitor/IDeviceMonitor.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
#include <libudev.h>
|
||||||
|
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
class UdevDeviceMonitor : public IDeviceMonitor
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit UdevDeviceMonitor(QObject* parent = nullptr);
|
||||||
|
~UdevDeviceMonitor() override;
|
||||||
|
|
||||||
|
bool start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onReadable();
|
||||||
|
DeviceEvent toEvent(struct udev_device* dev, const char* action);
|
||||||
|
static QString getProp(struct udev_device* dev, const char* key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct udev* m_udev{nullptr};
|
||||||
|
struct udev_monitor* m_mon{nullptr};
|
||||||
|
int m_fd{-1};
|
||||||
|
QSocketNotifier* m_notifier{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
42
src/device_bus/monitor/WindowsDeviceMonitor.cpp
Normal file
42
src/device_bus/monitor/WindowsDeviceMonitor.cpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include "device_bus/monitor/WindowsDeviceMonitor.h"
|
||||||
|
|
||||||
|
#include "utils/logs/logging.h"
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
WindowsDeviceMonitor::WindowsDeviceMonitor(QObject* parent)
|
||||||
|
: IDeviceMonitor(parent)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// real impl allocated in start()
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowsDeviceMonitor::~WindowsDeviceMonitor()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsDeviceMonitor::start()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// TODO: Implement WM_DEVICECHANGE + SetupAPI + NotifyIpInterfaceChange.
|
||||||
|
// Keep as stub for now to allow Linux builds; Windows build will need completing.
|
||||||
|
LOG_INFO() << "WindowsDeviceMonitor started (stub)";
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
LOG_WARNING() << "WindowsDeviceMonitor is not available on this platform";
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsDeviceMonitor::stop()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
LOG_INFO() << "WindowsDeviceMonitor stopped (stub)";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
27
src/device_bus/monitor/WindowsDeviceMonitor.h
Normal file
27
src/device_bus/monitor/WindowsDeviceMonitor.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "device_bus/monitor/IDeviceMonitor.h"
|
||||||
|
|
||||||
|
namespace softbus::device_bus::monitor
|
||||||
|
{
|
||||||
|
|
||||||
|
// Windows 实现:仅在 _WIN32 下启用;在其他平台上会是一个空实现以保证可编译。
|
||||||
|
class WindowsDeviceMonitor : public IDeviceMonitor
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit WindowsDeviceMonitor(QObject* parent = nullptr);
|
||||||
|
~WindowsDeviceMonitor() override;
|
||||||
|
|
||||||
|
bool start() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(_WIN32)
|
||||||
|
struct Impl;
|
||||||
|
Impl* d{nullptr};
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace softbus::device_bus::monitor
|
||||||
|
|
||||||
Reference in New Issue
Block a user