设备监控-回写

This commit is contained in:
flower_linux
2026-03-20 17:19:29 +08:00
parent 903c349e1d
commit 51fa0bb51b
27 changed files with 402 additions and 19 deletions

View File

@@ -100,6 +100,8 @@ qt_add_executable(softbus_daemon
# device bus: registry skeleton
src/device_bus/registry/IDeviceRegistry.h
src/device_bus/registry/DeviceRegistry.h
src/device_bus/registry/DeviceRegistry.cpp
# devices: base skeleton
src/devices/base/IDevice.h

Binary file not shown.

View File

@@ -10,6 +10,11 @@
void signalHandler(int signal)
{
LOG_INFO() << "Received signal:" << signal;
CoreService* coreService = CoreService::instance();
if (coreService) {
coreService->shutdown();
}
QCoreApplication::quit();
}
@@ -68,7 +73,7 @@ int main(int argc, char *argv[])
LOG_ERROR() << "CoreService initialize failed";
return 1;
}
QObject::connect(&app, &QCoreApplication::aboutToQuit, coreService, &CoreService::shutdown);
// QObject::connect(&app, &QCoreApplication::aboutToQuit, coreService, &CoreService::shutdown);
// ========================================================================
// 创建并注册 D-Bus 服务(仅在 CoreRouter 角色中启用)

View File

@@ -24,7 +24,7 @@ CoreService::CoreService(QObject* parent)
CoreService::~CoreService()
{
shutdown();
}
bool CoreService::initialize()

View File

@@ -7,6 +7,7 @@
#include "device_bus/manager/DeviceBusManager.h"
#include "device_bus/monitor/DeviceMonitorService.h"
#include "device_bus/registry/DeviceRegistry.h"
#include "device_bus/tree/DeviceTreeModel.h"
#include "utils/logs/logging.h"
@@ -14,11 +15,12 @@ namespace softbus::device_bus {
class DeviceBus::Impl {
public:
DeviceBusManager manager;
std::unique_ptr<DeviceBusManager> manager;
std::unique_ptr<monitor::DeviceMonitorService> monitorService;
std::unique_ptr<registry::DeviceRegistry> registry;
std::shared_ptr<DeviceTreeModel> treeModel;
QString configPath;
bool deviceTreeDirty{false};
bool deviceTreeDirty{false}; // 设备树是否脏了
};
DeviceBus &DeviceBus::instance() {
@@ -34,37 +36,61 @@ DeviceBus::~DeviceBus() {
}
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) {
return false;
}
if (!d->treeModel) {
d->treeModel = std::make_shared<DeviceTreeModel>();
}
d->manager.setDeviceTreeModel(d->treeModel);
return d->manager.initialize(rootConfig);
if (!d->manager) {
d->manager = std::make_unique<DeviceBusManager>();
}
if (!d->registry) {
d->registry = std::make_unique<registry::DeviceRegistry>(d->treeModel);
}
d->manager->setDeviceTreeModel(d->treeModel);
d->manager->setRegistry(d->registry.get());
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);
}
void DeviceBus::shutdown() {
if (!d) {
return;
}
if (d->monitorService) {
LOG_INFO() << "DeviceBus shutting down monitor service";
d->monitorService->stop();
d->monitorService.reset();
}
d->manager.shutdown();
if (d->manager) {
LOG_INFO() << "DeviceBus shutting down manager";
d->manager->shutdown();
}
if (!d->deviceTreeDirty) {
LOG_INFO() << "DeviceBus device tree dirty is false";
return;
}
if (d->configPath.isEmpty() || !d->treeModel) {
return;
}
const QFileInfo fi(d->configPath);
const QString dirPath = fi.dir().absolutePath();
LOG_INFO() << "DeviceBus: saving config to" << dirPath;
if (!QDir().mkpath(dirPath)) {
LOG_ERROR() << "DeviceBus: failed to create config dir" << dirPath;
return;
@@ -92,18 +118,22 @@ void DeviceBus::shutdown() {
}
void DeviceBus::setConfigPath(const QString& path) {
if (!d) return;
d->configPath = path;
}
QString DeviceBus::configPath() const {
if (!d) return {};
return d->configPath;
}
std::shared_ptr<DeviceTreeModel> DeviceBus::deviceTreeModel() const {
if (!d) return {};
return d->treeModel;
}
void DeviceBus::markDeviceTreeDirty() {
if (!d) return;
d->deviceTreeDirty = true;
}

View File

@@ -4,7 +4,7 @@
#include <QJsonDocument>
#include <QSerialPort>
#include <algorithm>
// #include <algorithm>
#include "hardware/drivers/serial/SerialQtDriver.h"
#include "hardware/drivers/serial/SerialCapabilities.h"
@@ -19,6 +19,11 @@ void DeviceBusManager::setDeviceTreeModel(std::shared_ptr<DeviceTreeModel> model
m_treeModel = std::move(model);
}
void DeviceBusManager::setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry)
{
m_registry = registry;
}
bool DeviceBusManager::initialize(const QJsonObject& rootConfig)
{
if (!m_treeModel) {

View File

@@ -17,6 +17,7 @@ class DeviceBusManager
{
public:
void setDeviceTreeModel(std::shared_ptr<DeviceTreeModel> model);
void setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry);
bool initialize(const QJsonObject& rootConfig);
void shutdown();

View File

@@ -2,6 +2,7 @@
#include <QJsonDocument>
#include "device_bus/registry/IDeviceRegistry.h"
#include "utils/logs/logging.h"
#if defined(__linux__)
@@ -57,6 +58,16 @@ void DeviceMonitorService::stop()
m_started = false;
}
void DeviceMonitorService::setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry)
{
m_registry = registry;
}
void DeviceMonitorService::setDirtyCallback(std::function<void()> cb)
{
m_dirtyCb = std::move(cb);
}
void DeviceMonitorService::onEvent(const DeviceEvent& ev)
{
// De-dup (short window): suppress identical events bursts
@@ -78,6 +89,18 @@ void DeviceMonitorService::onEvent(const DeviceEvent& ev)
}
m_lastEventMsByKey.insert(key, nowMs);
if (m_registry) {
bool changed = false;
if (ev.action == DeviceEventAction::Add || ev.action == DeviceEventAction::Change) {
changed = m_registry->upsertFromMonitorEvent(ev);
} else if (ev.action == DeviceEventAction::Remove) {
changed = m_registry->markOfflineFromMonitorEvent(ev);
}
if (changed && m_dirtyCb) {
m_dirtyCb();
}
}
// 第一版:仅日志
LOG_INFO() << "DeviceMonitor event"
<< "type=" << toString(ev.type)

View File

@@ -5,9 +5,12 @@
#include <vector>
#include <QHash>
#include <QDateTime>
#include <functional>
#include "device_bus/monitor/IDeviceMonitor.h"
namespace softbus::device_bus::registry { class IDeviceRegistry; }
namespace softbus::device_bus::monitor
{
@@ -20,6 +23,8 @@ public:
bool start();
void stop();
void setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry);
void setDirtyCallback(std::function<void()> cb);
private:
void onEvent(const DeviceEvent& ev);
@@ -27,6 +32,8 @@ private:
private:
std::vector<std::unique_ptr<IDeviceMonitor>> m_monitors;
bool m_started{false};
softbus::device_bus::registry::IDeviceRegistry* m_registry{nullptr};
std::function<void()> m_dirtyCb;
// Lightweight de-dup: key -> last timestamp (ms)
QHash<QString, qint64> m_lastEventMsByKey;

View File

@@ -0,0 +1,166 @@
#include "device_bus/registry/DeviceRegistry.h"
#include <QCryptographicHash>
#include <QDateTime>
#include "utils/logs/logging.h"
namespace softbus::device_bus::registry
{
DeviceRegistry::DeviceRegistry(std::shared_ptr<DeviceTreeModel> treeModel)
: m_treeModel(std::move(treeModel))
{
}
void DeviceRegistry::registerDevice(const softbus::devices::DeviceInfo& info)
{
m_devicesById.insert(info.id, info);
}
void DeviceRegistry::unregisterDevice(int id)
{
m_devicesById.remove(id);
}
std::optional<softbus::devices::DeviceInfo> DeviceRegistry::findById(int id) const
{
auto it = m_devicesById.constFind(id);
if (it == m_devicesById.constEnd()) {
return std::nullopt;
}
return it.value();
}
std::vector<softbus::devices::DeviceInfo> DeviceRegistry::listDevices() const
{
std::vector<softbus::devices::DeviceInfo> out;
out.reserve(m_devicesById.size());
for (auto it = m_devicesById.cbegin(); it != m_devicesById.cend(); ++it) {
out.push_back(it.value());
}
return out;
}
bool DeviceRegistry::upsertFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev)
{
if (!m_treeModel) return false;
const QString stableKey = buildStableKey(ev);
if (stableKey.isEmpty()) {
return false;
}
const QString preferredId = buildPreferredNodeId(ev, stableKey);
const QString now = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
const QString nodeId = m_treeModel->upsertNodeByStableKey(
stableKey,
preferredId,
inferType(ev),
inferEndpoint(ev),
inferName(ev),
buildParams(ev),
true,
now);
if (!nodeId.isEmpty()) {
m_stableKeyToNodeId.insert(stableKey, nodeId);
return true;
}
return false;
}
bool DeviceRegistry::markOfflineFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev)
{
if (!m_treeModel) return false;
const QString stableKey = buildStableKey(ev);
if (stableKey.isEmpty()) {
return false;
}
const QString now = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
return m_treeModel->markOfflineByStableKey(stableKey, now);
}
QString DeviceRegistry::buildStableKey(const softbus::device_bus::monitor::DeviceEvent& ev)
{
const QString type = inferType(ev);
if (!ev.serial.isEmpty()) {
return type + QStringLiteral("|serial|") + ev.serial;
}
if (ev.type == softbus::device_bus::monitor::DeviceEventType::NetInterface) {
if (!ev.ifname.isEmpty()) return type + QStringLiteral("|ifname|") + ev.ifname;
if (ev.ifindex >= 0) return type + QStringLiteral("|ifindex|") + QString::number(ev.ifindex);
}
const QString path = !ev.props.value(QStringLiteral("SYSPATH")).isEmpty()
? ev.props.value(QStringLiteral("SYSPATH"))
: (!ev.devicePath.isEmpty() ? ev.devicePath : ev.devnode);
if (!ev.vid.isEmpty() || !ev.pid.isEmpty() || !path.isEmpty()) {
return type + QStringLiteral("|vpidpath|") + ev.vid + QStringLiteral(":") + ev.pid + QStringLiteral("|") + path;
}
if (!ev.devnode.isEmpty()) {
return type + QStringLiteral("|devnode|") + ev.devnode;
}
return {};
}
QString DeviceRegistry::buildPreferredNodeId(const softbus::device_bus::monitor::DeviceEvent& ev, const QString& stableKey)
{
if (!ev.serial.isEmpty()) {
return QStringLiteral("dev_serial_") + ev.serial;
}
const QByteArray hash = QCryptographicHash::hash(stableKey.toUtf8(), QCryptographicHash::Sha1).toHex();
return QStringLiteral("dev_") + QString::fromUtf8(hash.left(12));
}
QString DeviceRegistry::inferType(const softbus::device_bus::monitor::DeviceEvent& ev)
{
using softbus::device_bus::monitor::DeviceEventType;
switch (ev.type) {
case DeviceEventType::Serial: return QStringLiteral("serial");
case DeviceEventType::NetInterface: return QStringLiteral("network");
case DeviceEventType::Storage: return QStringLiteral("storage");
case DeviceEventType::Usb: return QStringLiteral("usb");
default: return QStringLiteral("unknown");
}
}
QString DeviceRegistry::inferEndpoint(const softbus::device_bus::monitor::DeviceEvent& ev)
{
if (!ev.devnode.isEmpty()) return ev.devnode;
if (!ev.ifname.isEmpty()) return ev.ifname;
if (!ev.devicePath.isEmpty()) return ev.devicePath;
return ev.props.value(QStringLiteral("SYSPATH"));
}
QString DeviceRegistry::inferName(const softbus::device_bus::monitor::DeviceEvent& ev)
{
if (!ev.model.isEmpty()) return ev.model;
if (!ev.ifname.isEmpty()) return ev.ifname;
if (!ev.devnode.isEmpty()) return ev.devnode;
return inferType(ev);
}
QJsonObject DeviceRegistry::buildParams(const softbus::device_bus::monitor::DeviceEvent& ev)
{
QJsonObject p;
p.insert(QStringLiteral("online"), true);
if (!ev.vid.isEmpty()) p.insert(QStringLiteral("vid"), ev.vid);
if (!ev.pid.isEmpty()) p.insert(QStringLiteral("pid"), ev.pid);
if (!ev.serial.isEmpty()) p.insert(QStringLiteral("serial"), ev.serial);
if (!ev.vendor.isEmpty()) p.insert(QStringLiteral("vendor"), ev.vendor);
if (!ev.model.isEmpty()) p.insert(QStringLiteral("model"), ev.model);
if (!ev.ifname.isEmpty()) p.insert(QStringLiteral("ifname"), ev.ifname);
if (ev.ifindex >= 0) p.insert(QStringLiteral("ifindex"), ev.ifindex);
if (!ev.subsystem.isEmpty()) p.insert(QStringLiteral("subsystem"), ev.subsystem);
if (!ev.devicePath.isEmpty()) p.insert(QStringLiteral("devicePath"), ev.devicePath);
if (!ev.devnode.isEmpty()) p.insert(QStringLiteral("devnode"), ev.devnode);
return p;
}
} // namespace softbus::device_bus::registry

View File

@@ -0,0 +1,44 @@
#pragma once
#include <QHash>
#include <memory>
#include <optional>
#include <vector>
#include "device_bus/registry/IDeviceRegistry.h"
#include "device_bus/tree/DeviceTreeModel.h"
namespace softbus::device_bus::registry
{
class DeviceRegistry : public IDeviceRegistry
{
public:
explicit DeviceRegistry(std::shared_ptr<DeviceTreeModel> treeModel);
~DeviceRegistry() override = default;
void registerDevice(const softbus::devices::DeviceInfo& info) override;
void unregisterDevice(int id) override;
std::optional<softbus::devices::DeviceInfo> findById(int id) const override;
std::vector<softbus::devices::DeviceInfo> listDevices() const override;
bool upsertFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) override;
bool markOfflineFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) override;
private:
static QString buildStableKey(const softbus::device_bus::monitor::DeviceEvent& ev);
static QString buildPreferredNodeId(const softbus::device_bus::monitor::DeviceEvent& ev, const QString& stableKey);
static QString inferType(const softbus::device_bus::monitor::DeviceEvent& ev);
static QString inferEndpoint(const softbus::device_bus::monitor::DeviceEvent& ev);
static QString inferName(const softbus::device_bus::monitor::DeviceEvent& ev);
static QJsonObject buildParams(const softbus::device_bus::monitor::DeviceEvent& ev);
private:
std::shared_ptr<DeviceTreeModel> m_treeModel;
QHash<int, softbus::devices::DeviceInfo> m_devicesById;
QHash<QString, QString> m_stableKeyToNodeId;
};
} // namespace softbus::device_bus::registry

View File

@@ -4,6 +4,7 @@
#include <vector>
#include "devices/DeviceTypes.h"
#include "device_bus/monitor/DeviceEvent.h"
namespace softbus::device_bus::registry
{
@@ -18,6 +19,10 @@ public:
virtual std::optional<softbus::devices::DeviceInfo> findById(int id) const = 0;
virtual std::vector<softbus::devices::DeviceInfo> listDevices() const = 0;
// Monitor-driven registry APIs
virtual bool upsertFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) = 0;
virtual bool markOfflineFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) = 0;
};
} // namespace softbus::device_bus::registry

View File

@@ -118,14 +118,96 @@ QJsonObject DeviceTreeModel::toDaemonConfigRoot() const
const DeviceTreeNode* DeviceTreeModel::findById(const QString& id) const
{
const auto it = m_indexById.constFind(id);
if (it == m_indexById.constEnd()) {
return nullptr;
}
const int index = it.value();
const int index = findIndexById(id);
if (index < 0 || index >= m_nodes.size()) {
return nullptr;
}
return &m_nodes.at(index);
}
int DeviceTreeModel::findIndexById(const QString& id) const
{
const auto it = m_indexById.constFind(id);
if (it == m_indexById.constEnd()) {
return -1;
}
return it.value();
}
int DeviceTreeModel::findIndexByStableKey(const QString& stableKey) const
{
if (stableKey.isEmpty()) {
return -1;
}
for (int i = 0; i < m_nodes.size(); ++i) {
const auto& n = m_nodes.at(i);
if (n.params.value(QStringLiteral("stableKey")).toString() == stableKey) {
return i;
}
}
return -1;
}
QString DeviceTreeModel::upsertNodeByStableKey(const QString& stableKey,
const QString& preferredId,
const QString& type,
const QString& endpoint,
const QString& name,
const QJsonObject& extraParams,
bool online,
const QString& lastSeenTs)
{
int idx = findIndexByStableKey(stableKey);
if (idx < 0 && !preferredId.isEmpty()) {
idx = findIndexById(preferredId);
}
if (idx < 0) {
DeviceTreeNode node;
node.id = preferredId;
node.type = type;
node.endpoint = endpoint;
node.name = name;
node.enabled = true;
node.params = extraParams;
node.params.insert(QStringLiteral("stableKey"), stableKey);
node.params.insert(QStringLiteral("online"), online);
if (!lastSeenTs.isEmpty()) {
node.params.insert(QStringLiteral("lastSeenTs"), lastSeenTs);
}
m_nodes.push_back(node);
rebuildIndex();
return node.id;
}
auto& node = m_nodes[idx];
if (!type.isEmpty()) node.type = type;
if (!endpoint.isEmpty()) node.endpoint = endpoint;
if (!name.isEmpty()) node.name = name;
node.enabled = true;
for (auto it = extraParams.begin(); it != extraParams.end(); ++it) {
node.params.insert(it.key(), it.value());
}
node.params.insert(QStringLiteral("stableKey"), stableKey);
node.params.insert(QStringLiteral("online"), online);
if (!lastSeenTs.isEmpty()) {
node.params.insert(QStringLiteral("lastSeenTs"), lastSeenTs);
}
return node.id;
}
bool DeviceTreeModel::markOfflineByStableKey(const QString& stableKey, const QString& lastSeenTs)
{
const int idx = findIndexByStableKey(stableKey);
if (idx < 0) {
return false;
}
auto& node = m_nodes[idx];
node.params.insert(QStringLiteral("online"), false);
if (!lastSeenTs.isEmpty()) {
node.params.insert(QStringLiteral("lastSeenTs"), lastSeenTs);
}
return true;
}

View File

@@ -31,6 +31,19 @@ public:
QVector<DeviceTreeNode>& nodesMutable() { return m_nodes; }
const DeviceTreeNode* findById(const QString& id) const;
int findIndexById(const QString& id) const;
int findIndexByStableKey(const QString& stableKey) const;
// Monitor/register path: upsert or mark online/offline
QString upsertNodeByStableKey(const QString& stableKey,
const QString& preferredId,
const QString& type,
const QString& endpoint,
const QString& name,
const QJsonObject& extraParams,
bool online,
const QString& lastSeenTs);
bool markOfflineByStableKey(const QString& stableKey, const QString& lastSeenTs);
// 序列化为 daemon_config.json 所需格式
QJsonArray toDeviceTreeJson() const;