设备监控-过滤
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10
main.cpp
10
main.cpp
@@ -14,7 +14,7 @@ void signalHandler(int signal)
|
||||
if (coreService) {
|
||||
coreService->shutdown();
|
||||
}
|
||||
|
||||
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
@@ -67,6 +67,14 @@ int main(int argc, char *argv[])
|
||||
<< "valid roles are: CoreRouter, CollectorSerial, CollectorCan, Collector, SqlServer";
|
||||
return 1;
|
||||
}
|
||||
// 开启coreserive的初始化工作|线程
|
||||
// QThread* coreServiceThread = new QThread();
|
||||
// CoreService* coreService = new CoreService();
|
||||
// coreService->moveToThread(coreServiceThread);
|
||||
// QObject::connect(coreServiceThread, &QThread::started, coreService, &CoreService::initialize);
|
||||
// QObject::connect(coreServiceThread, &QThread::finished, coreService, &CoreService::deleteLater);
|
||||
// QObject::connect(coreServiceThread, &QThread::finished, coreServiceThread, &QThread::deleteLater);
|
||||
// coreServiceThread->start();
|
||||
|
||||
CoreService* coreService = CoreService::instance();
|
||||
if (!coreService->initialize()) {
|
||||
|
||||
@@ -52,15 +52,27 @@ bool DeviceBus::initialize(const QJsonObject &rootConfig) {
|
||||
d->manager->setDeviceTreeModel(d->treeModel);
|
||||
d->manager->setRegistry(d->registry.get());
|
||||
|
||||
// 1) Load persisted config and initialize manager
|
||||
if (!d->manager->initialize(rootConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2) Start monitor service
|
||||
if (!d->monitorService) {
|
||||
d->monitorService = std::make_unique<monitor::DeviceMonitorService>(nullptr);
|
||||
d->monitorService->setRegistry(d->registry.get());
|
||||
d->monitorService->setDirtyCallback([this]() { this->markDeviceTreeDirty(); });
|
||||
if (!d->monitorService->start()) {
|
||||
LOG_WARNING() << "DeviceBus: device monitor service start failed";
|
||||
}
|
||||
}
|
||||
return d->manager->initialize(rootConfig);
|
||||
if (!d->monitorService->start()) {
|
||||
LOG_WARNING() << "DeviceBus: device monitor service start failed";
|
||||
}
|
||||
|
||||
// 3) Initial snapshot scan (register existing devices)
|
||||
d->monitorService->initialScan();
|
||||
|
||||
// 4) Reconcile runtime instances against latest tree model
|
||||
d->manager->reconcileFromTreeModel();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceBus::shutdown() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QSerialPort>
|
||||
#include <QSet>
|
||||
// #include <algorithm>
|
||||
|
||||
#include "hardware/drivers/serial/SerialQtDriver.h"
|
||||
@@ -58,6 +59,44 @@ bool DeviceBusManager::initialize(const QJsonObject& rootConfig)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceBusManager::reconcileFromTreeModel()
|
||||
{
|
||||
if (!m_treeModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QSet<QString> desiredSerialEndpoints;
|
||||
const auto nodes = m_treeModel->nodes();
|
||||
for (const auto& n : nodes) {
|
||||
if (!n.enabled) continue;
|
||||
if (!n.params.value(QStringLiteral("online")).toBool(true)) continue;
|
||||
|
||||
auto kind = softbus::devices::kindFromType(n.type);
|
||||
if (kind == softbus::devices::DeviceKind::Unknown) {
|
||||
kind = softbus::devices::inferDeviceKindFromEndpoint(n.endpoint);
|
||||
}
|
||||
|
||||
if (kind == softbus::devices::DeviceKind::Serial) {
|
||||
desiredSerialEndpoints.insert(n.endpoint);
|
||||
if (!m_serialDevicesByEndpoint.contains(n.endpoint)) {
|
||||
initializeSerialDevice(n.endpoint, n.params);
|
||||
}
|
||||
m_deviceEndpointsMap.insert(n.endpoint, kind);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove runtime devices that are no longer desired/offline
|
||||
const auto currentKeys = m_serialDevicesByEndpoint.keys();
|
||||
for (const auto& endpoint : currentKeys) {
|
||||
if (!desiredSerialEndpoints.contains(endpoint)) {
|
||||
shutdownSerialDevice(endpoint);
|
||||
m_deviceEndpointsMap.remove(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceBusManager::shutdown()
|
||||
{
|
||||
// 关闭并销毁所有串口设备
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
void setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry);
|
||||
|
||||
bool initialize(const QJsonObject& rootConfig);
|
||||
bool reconcileFromTreeModel();
|
||||
void shutdown();
|
||||
|
||||
private:
|
||||
|
||||
@@ -49,6 +49,19 @@ bool DeviceMonitorService::start()
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool DeviceMonitorService::initialScan()
|
||||
{
|
||||
bool any = false;
|
||||
for (auto& m : m_monitors) {
|
||||
const auto snapshot = m->snapshotExisting();
|
||||
for (const auto& ev : snapshot) {
|
||||
onEvent(ev);
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
return any;
|
||||
}
|
||||
|
||||
void DeviceMonitorService::stop()
|
||||
{
|
||||
if (!m_started) return;
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
|
||||
bool start();
|
||||
void stop();
|
||||
bool initialScan();
|
||||
void setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry);
|
||||
void setDirtyCallback(std::function<void()> cb);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
@@ -20,6 +21,7 @@ public:
|
||||
|
||||
virtual bool start() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual std::vector<DeviceEvent> snapshotExisting() = 0;
|
||||
|
||||
void setCallback(EventCallback cb) { m_cb = std::move(cb); }
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
@@ -149,6 +150,38 @@ void NetlinkDeviceMonitor::onReadable()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DeviceEvent> NetlinkDeviceMonitor::snapshotExisting()
|
||||
{
|
||||
std::vector<DeviceEvent> out;
|
||||
|
||||
ifaddrs* ifaddr = nullptr;
|
||||
if (::getifaddrs(&ifaddr) != 0) {
|
||||
return out;
|
||||
}
|
||||
|
||||
QSet<QString> seen;
|
||||
for (ifaddrs* it = ifaddr; it != nullptr; it = it->ifa_next) {
|
||||
if (!it->ifa_name) continue;
|
||||
|
||||
const QString ifname = QString::fromUtf8(it->ifa_name);
|
||||
if (ifname.isEmpty() || seen.contains(ifname)) continue;
|
||||
seen.insert(ifname);
|
||||
|
||||
DeviceEvent ev;
|
||||
ev.timestamp = QDateTime::currentDateTimeUtc();
|
||||
ev.type = DeviceEventType::NetInterface;
|
||||
ev.action = DeviceEventAction::Add;
|
||||
ev.subsystem = QStringLiteral("net");
|
||||
ev.ifname = ifname;
|
||||
ev.ifindex = ::if_nametoindex(it->ifa_name);
|
||||
ev.linkUp = (it->ifa_flags & IFF_RUNNING) != 0;
|
||||
out.push_back(ev);
|
||||
}
|
||||
|
||||
::freeifaddrs(ifaddr);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace softbus::device_bus::monitor
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QSocketNotifier>
|
||||
#include <QSet>
|
||||
#include <QHash>
|
||||
#include <vector>
|
||||
|
||||
namespace softbus::device_bus::monitor
|
||||
{
|
||||
@@ -20,6 +21,7 @@ public:
|
||||
|
||||
bool start() override;
|
||||
void stop() override;
|
||||
std::vector<DeviceEvent> snapshotExisting() override;
|
||||
|
||||
private:
|
||||
void onReadable();
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
@@ -10,6 +12,37 @@
|
||||
|
||||
namespace softbus::device_bus::monitor
|
||||
{
|
||||
namespace {
|
||||
|
||||
bool isWhitelistedSerialDevnode(const QString& devnode)
|
||||
{
|
||||
if (devnode.startsWith(QStringLiteral("/dev/ttyUSB"))) return true;
|
||||
if (devnode.startsWith(QStringLiteral("/dev/ttyACM"))) return true;
|
||||
|
||||
// Board UART allowlist: ttyS1 ~ ttyS6
|
||||
static const QRegularExpression kTtySRe(QStringLiteral("^/dev/ttyS(\\d+)$"));
|
||||
const auto m = kTtySRe.match(devnode);
|
||||
if (m.hasMatch()) {
|
||||
bool ok = false;
|
||||
const int n = m.captured(1).toInt(&ok);
|
||||
if (ok && n >= 1 && n <= 6) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isConsoleLikeTty(const QString& devnode)
|
||||
{
|
||||
if (devnode == QStringLiteral("/dev/console")) return true;
|
||||
if (devnode == QStringLiteral("/dev/tty")) return true;
|
||||
if (devnode == QStringLiteral("/dev/ptmx")) return true;
|
||||
if (devnode.startsWith(QStringLiteral("/dev/pts/"))) return true;
|
||||
|
||||
// Linux VT consoles: /dev/tty0.../dev/tty63 (without 'S')
|
||||
static const QRegularExpression kVtRe(QStringLiteral("^/dev/tty(\\d+)$"));
|
||||
return kVtRe.match(devnode).hasMatch();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UdevDeviceMonitor::UdevDeviceMonitor(QObject* parent)
|
||||
: IDeviceMonitor(parent)
|
||||
@@ -94,35 +127,7 @@ void UdevDeviceMonitor::onReadable()
|
||||
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) {
|
||||
if (!shouldKeepEvent(ev)) {
|
||||
udev_device_unref(dev);
|
||||
continue;
|
||||
}
|
||||
@@ -132,6 +137,117 @@ void UdevDeviceMonitor::onReadable()
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DeviceEvent> UdevDeviceMonitor::snapshotExisting()
|
||||
{
|
||||
std::vector<DeviceEvent> out;
|
||||
if (!m_udev) {
|
||||
// Snapshot can be requested before start(); create temp context.
|
||||
m_udev = udev_new();
|
||||
if (!m_udev) {
|
||||
LOG_ERROR() << "UdevDeviceMonitor: snapshot udev_new failed";
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
udev_enumerate* en = udev_enumerate_new(m_udev);
|
||||
if (!en) {
|
||||
return out;
|
||||
}
|
||||
|
||||
udev_enumerate_add_match_subsystem(en, "tty");
|
||||
udev_enumerate_add_match_subsystem(en, "usb");
|
||||
udev_enumerate_add_match_subsystem(en, "block");
|
||||
if (udev_enumerate_scan_devices(en) != 0) {
|
||||
udev_enumerate_unref(en);
|
||||
return out;
|
||||
}
|
||||
|
||||
udev_list_entry* devices = udev_enumerate_get_list_entry(en);
|
||||
udev_list_entry* entry = nullptr;
|
||||
udev_list_entry_foreach(entry, devices) {
|
||||
const char* path = udev_list_entry_get_name(entry);
|
||||
if (!path) continue;
|
||||
|
||||
udev_device* dev = udev_device_new_from_syspath(m_udev, path);
|
||||
if (!dev) continue;
|
||||
|
||||
DeviceEvent ev = toEvent(dev, "add");
|
||||
if (shouldKeepEvent(ev)) {
|
||||
out.push_back(ev);
|
||||
}
|
||||
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
|
||||
udev_enumerate_unref(en);
|
||||
return out;
|
||||
}
|
||||
|
||||
bool UdevDeviceMonitor::shouldKeepEvent(const DeviceEvent& ev) const
|
||||
{
|
||||
// Drop unknown action (usually noise / incomplete events)
|
||||
if (ev.action == DeviceEventAction::Unknown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Serial tty: keep only business serial nodes.
|
||||
if (ev.subsystem == QStringLiteral("tty")) {
|
||||
if (ev.devnode.isEmpty()) {
|
||||
LOG_ERROR() << "UdevDeviceMonitor: devnode is empty" << ev.devnode;
|
||||
return false;
|
||||
}
|
||||
if (isConsoleLikeTty(ev.devnode)) {
|
||||
LOG_INFO() << "UdevDeviceMonitor: console like tty" << ev.devnode;
|
||||
return false;
|
||||
}
|
||||
if (!isWhitelistedSerialDevnode(ev.devnode)) {
|
||||
LOG_INFO() << "UdevDeviceMonitor: not whitelisted serial devnode" << ev.devnode;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 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")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Drop most "change" spam for usb (keep add/remove)
|
||||
if (ev.action == DeviceEventAction::Change) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it carries no stable identifiers, it's not useful
|
||||
if (ev.devnode.isEmpty() && ev.vid.isEmpty() && ev.pid.isEmpty() && ev.serial.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Drop Linux root hubs/controller pseudo devices.
|
||||
if (ev.vid == QStringLiteral("1d6b")) {
|
||||
return false;
|
||||
}
|
||||
const QString modelLower = ev.model.toLower();
|
||||
if (modelLower.contains(QStringLiteral("hub")) ||
|
||||
modelLower.contains(QStringLiteral("host_controller")) ||
|
||||
modelLower.contains(QStringLiteral("xhci"))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Block: keep only usb-backed storage add/remove, drop non-storage blocks.
|
||||
if (ev.subsystem == QStringLiteral("block")) {
|
||||
if (ev.type != DeviceEventType::Storage) {
|
||||
return false;
|
||||
}
|
||||
if (ev.action == DeviceEventAction::Change) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString UdevDeviceMonitor::getProp(struct udev_device* dev, const char* key)
|
||||
{
|
||||
if (!dev || !key) return {};
|
||||
|
||||
@@ -20,9 +20,11 @@ public:
|
||||
|
||||
bool start() override;
|
||||
void stop() override;
|
||||
std::vector<DeviceEvent> snapshotExisting() override;
|
||||
|
||||
private:
|
||||
void onReadable();
|
||||
bool shouldKeepEvent(const DeviceEvent& ev) const;
|
||||
DeviceEvent toEvent(struct udev_device* dev, const char* action);
|
||||
static QString getProp(struct udev_device* dev, const char* key);
|
||||
|
||||
|
||||
@@ -38,5 +38,11 @@ void WindowsDeviceMonitor::stop()
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<DeviceEvent> WindowsDeviceMonitor::snapshotExisting()
|
||||
{
|
||||
// TODO: implement full snapshot on Windows.
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace softbus::device_bus::monitor
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
|
||||
bool start() override;
|
||||
void stop() override;
|
||||
std::vector<DeviceEvent> snapshotExisting() override;
|
||||
|
||||
private:
|
||||
#if defined(_WIN32)
|
||||
|
||||
@@ -85,6 +85,27 @@ QString DeviceRegistry::buildStableKey(const softbus::device_bus::monitor::Devic
|
||||
{
|
||||
const QString type = inferType(ev);
|
||||
|
||||
// Important: ttyACM/ttyUSB 可能“同一条物理设备多路口”但 serial 相同,
|
||||
// 旧逻辑会导致 stableKey 冲突并相互覆盖 endpoint。
|
||||
// tty 事件:devnode 必须用于唯一标识(ttyACM 可能多路口但 serial 可能相同)。
|
||||
// 若具备 SYSPATH,也一并拼接,便于跨层级归并与排查。
|
||||
if (ev.type == softbus::device_bus::monitor::DeviceEventType::Serial ||
|
||||
ev.subsystem == QStringLiteral("tty")) {
|
||||
const QString syspath = ev.props.value(QStringLiteral("SYSPATH"));
|
||||
if (!ev.devnode.isEmpty()) {
|
||||
if (!syspath.isEmpty()) {
|
||||
return type + QStringLiteral("|syspath|") + syspath + QStringLiteral("|devnode|") + ev.devnode;
|
||||
}
|
||||
return type + QStringLiteral("|devnode|") + ev.devnode;
|
||||
}
|
||||
if (!syspath.isEmpty()) {
|
||||
return type + QStringLiteral("|syspath|") + syspath;
|
||||
}
|
||||
if (!ev.serial.isEmpty()) {
|
||||
return type + QStringLiteral("|serial|") + ev.serial;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ev.serial.isEmpty()) {
|
||||
return type + QStringLiteral("|serial|") + ev.serial;
|
||||
}
|
||||
@@ -109,6 +130,15 @@ QString DeviceRegistry::buildStableKey(const softbus::device_bus::monitor::Devic
|
||||
|
||||
QString DeviceRegistry::buildPreferredNodeId(const softbus::device_bus::monitor::DeviceEvent& ev, const QString& stableKey)
|
||||
{
|
||||
// For tty devices (ttyS/ttyUSB/ttyACM...), a single physical device may expose
|
||||
// multiple ports that share the same serial. If we only use `serial` as id,
|
||||
// upsert() will collide by preferredId and overwrite endpoints.
|
||||
if (ev.type == softbus::device_bus::monitor::DeviceEventType::Serial ||
|
||||
ev.subsystem == QStringLiteral("tty")) {
|
||||
const QByteArray hash = QCryptographicHash::hash(stableKey.toUtf8(), QCryptographicHash::Sha1).toHex();
|
||||
return QStringLiteral("dev_") + QString::fromUtf8(hash.left(12));
|
||||
}
|
||||
|
||||
if (!ev.serial.isEmpty()) {
|
||||
return QStringLiteral("dev_serial_") + ev.serial;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user