Files
softbus_daemon/src/device_bus/manager/DeviceBusManager.cpp
flower_linux 7280fca08d dommessage
2026-04-28 21:56:56 +08:00

476 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "device_bus/manager/DeviceBusManager.h"
#include <chrono>
#include <memory>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QSaveFile>
#include <QSet>
// #include <algorithm>
#include "device_bus/DeviceBus.h"
#include "message_bus/egress/EgressRouter.h"
#include "message_bus/ingress/DriverIngressAdapter.h"
#include "message_bus/pipeline/PipelineEngine.h"
#include "core/metadata/ProfileRegistry.h"
#include "message_bus/pipeline/mapping/MappingRegistry.h"
#include "message_bus/pipeline/rules/DynamicRuleRegistry.h"
#include "core/plugin_system/PluginManager.h"
#include "device_bus/manager/SerialDeviceManager.h"
#include "devices/DeviceTypes.h"
#include "utils/logs/logging.h"
namespace
{
softbus::message_bus::pipeline::RuleScope parseRuleScope(const QJsonObject& obj)
{
softbus::message_bus::pipeline::RuleScope scope;
scope.endpointHash = static_cast<std::uint32_t>(obj.value(QStringLiteral("endpointHash")).toInteger(0));
scope.deviceId = obj.value(QStringLiteral("deviceId")).toInt(-1);
scope.stableKey = obj.value(QStringLiteral("stableKey")).toString();
return scope;
}
QString rulesConfigPath()
{
const QString daemonConfigPath = softbus::device_bus::DeviceBus::instance().configPath();
if (!daemonConfigPath.isEmpty()) {
const QFileInfo fi(daemonConfigPath);
return fi.dir().filePath(QStringLiteral("runtime_rules.json"));
}
return QDir::homePath() + QStringLiteral("/softbus/config/runtime_rules.json");
}
QString runtimeMappingsConfigPath()
{
const QFileInfo fi(rulesConfigPath());
return fi.dir().filePath(QStringLiteral("runtime_mappings.json"));
}
bool ensureConfigFileInitialized(const QString& targetPath,
const QString& fallbackPath,
const QByteArray& defaultContent,
const char* fileLabel)
{
if (QFile::exists(targetPath)) {
return true;
}
const QFileInfo fi(targetPath);
if (!QDir().mkpath(fi.dir().absolutePath())) {
LOG_WARNING() << "DeviceBusManager: failed to create config directory:" << fi.dir().absolutePath();
return false;
}
QByteArray initBytes = defaultContent;
QFile fallback(fallbackPath);
if (!fallbackPath.isEmpty() && fallback.exists() && fallback.open(QIODevice::ReadOnly)) {
initBytes = fallback.readAll();
}
QSaveFile initFile(targetPath);
if (!initFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
LOG_WARNING() << "DeviceBusManager: failed to create" << fileLabel << "file:" << targetPath;
return false;
}
if (initFile.write(initBytes) != initBytes.size()) {
LOG_WARNING() << "DeviceBusManager: failed to initialize" << fileLabel << "file:" << targetPath;
initFile.cancelWriting();
return false;
}
if (!initFile.commit()) {
LOG_WARNING() << "DeviceBusManager: failed to commit" << fileLabel << "file:" << targetPath;
return false;
}
LOG_INFO() << "DeviceBusManager: initialized" << fileLabel << "file:" << targetPath;
return true;
}
void ensureCoreConfigFilesInitialized()
{
const QFileInfo rulesFi(rulesConfigPath());
const QString baseDir = rulesFi.dir().absolutePath();
const QByteArray defaultRules = QJsonDocument(QJsonObject{
{QStringLiteral("filter"), QJsonArray{}},
{QStringLiteral("transform"), QJsonArray{}},
}).toJson(QJsonDocument::Indented);
(void)ensureConfigFileInitialized(rulesConfigPath(),
QStringLiteral(),
defaultRules,
"runtime_rules");
const QByteArray defaultMappings = QStringLiteral(
"{\n \"catalogVersion\": 1,\n \"items\": []\n}\n")
.toUtf8();
(void)ensureConfigFileInitialized(runtimeMappingsConfigPath(),
QStringLiteral(),
defaultMappings,
"runtime_mappings");
const QString profilesPath = QDir(baseDir).filePath(QStringLiteral("device_profiles.json"));
const QByteArray defaultProfiles = QStringLiteral(
"{\n \"catalogVersion\": \"\",\n \"profiles\": []\n}\n")
.toUtf8();
(void)ensureConfigFileInitialized(profilesPath,
QStringLiteral("config/device_profiles.json"),
defaultProfiles,
"device_profiles");
const QString metadataPath = QDir(baseDir).filePath(QStringLiteral("metadata_dictionary.json"));
const QByteArray defaultMetadata = QStringLiteral(
"{\n \"catalogVersion\": \"\",\n \"metadatas\": []\n}\n")
.toUtf8();
(void)ensureConfigFileInitialized(metadataPath,
QStringLiteral("config/metadata_dictionary.json"),
defaultMetadata,
"metadata_dictionary");
}
void loadRuntimeMappingsFromDedicatedConfig()
{
const QString path = runtimeMappingsConfigPath();
if (!softbus::message_bus::pipeline::MappingRegistry::instance().loadPersistedFile(path)) {
LOG_WARNING() << "DeviceBusManager: failed to load runtime_mappings from" << path;
} else {
LOG_INFO() << "DeviceBusManager: loaded runtime_mappings from" << path;
}
}
void loadProfileCatalogSingleton()
{
const QString dir = QFileInfo(rulesConfigPath()).dir().absolutePath();
const QString profilePath = QDir(dir).filePath(QStringLiteral("device_profiles.json"));
if (!softbus::core::metadata::ProfileRegistry::instance().loadFromFile(profilePath)) {
LOG_WARNING() << "DeviceBusManager: profile catalog load failed path=" << profilePath
<< "err=" << softbus::core::metadata::ProfileRegistry::instance().lastError();
} else {
LOG_INFO() << "DeviceBusManager: loaded device_profiles from" << profilePath;
}
}
void loadDynamicRulesFromDedicatedConfig()
{
auto& reg = softbus::message_bus::pipeline::DynamicRuleRegistry::instance();
const QString path = rulesConfigPath();
QFile file(path);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_WARNING() << "DeviceBusManager: failed to open rules config:" << path;
return;
}
QJsonParseError pe;
const QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &pe);
if (pe.error != QJsonParseError::NoError || !doc.isObject()) {
LOG_WARNING() << "DeviceBusManager: invalid rules config json:" << path << "err=" << pe.errorString();
return;
}
const QJsonObject rulesObj = doc.object();
const QJsonArray filterRules = rulesObj.value(QStringLiteral("filter")).toArray();
const QJsonArray transformRules = rulesObj.value(QStringLiteral("transform")).toArray();
int loadedFilterCount = 0;
for (const auto& item : filterRules) {
const QJsonObject obj = item.toObject();
softbus::message_bus::pipeline::FilterRule rule;
rule.id = obj.value(QStringLiteral("id")).toString();
rule.scope = parseRuleScope(obj.value(QStringLiteral("scope")).toObject());
rule.condition = obj.value(QStringLiteral("condition")).toObject();
if (!rule.id.isEmpty()) {
(void)reg.addFilterRule(rule);
++loadedFilterCount;
}
}
int loadedTransformCount = 0;
for (const auto& item : transformRules) {
const QJsonObject obj = item.toObject();
softbus::message_bus::pipeline::TransformRule rule;
rule.id = obj.value(QStringLiteral("id")).toString();
rule.scope = parseRuleScope(obj.value(QStringLiteral("scope")).toObject());
rule.scale = obj.value(QStringLiteral("scale")).toDouble(1.0);
rule.offset = obj.value(QStringLiteral("offset")).toDouble(0.0);
rule.unit = obj.value(QStringLiteral("unit")).toString();
if (!rule.id.isEmpty()) {
(void)reg.addTransformRule(rule);
++loadedTransformCount;
}
}
LOG_INFO() << "DeviceBusManager: loaded dynamic rules from" << path
<< "filter=" << loadedFilterCount
<< "transform=" << loadedTransformCount;
}
} // namespace
DeviceBusManager::~DeviceBusManager()
{
shutdown();
}
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;
}
void DeviceBusManager::setDirtyCallback(std::function<void()> cb)
{
m_dirtyCb = std::move(cb);
}
bool DeviceBusManager::initialize(const QJsonObject& rootConfig)
{
// 初始化内存池、pipeline引擎、插件管理器、ingress适配器、egress路由器
// 内存池是用来存储数据块的
// pipeline引擎是用来处理数据流的
// 插件管理器是用来管理插件的
// ingress适配器是用来将数据推送到 ingress 队列的
// egress路由器是用来将数据从 ingress 队列中取出并发送给设备的
// 内存池大小为4096每个数据块大小为4096
// pipeline引擎队列大小为4096
// 插件管理器插件数量为4096
// ingress适配器队列大小为4096
// egress路由器队列大小为4096
if (!m_memoryPool) {
m_memoryPool = std::make_shared<softbus::core::memory::MemoryPool>(4096, 4096);
}
if (!m_pipelineEngine) {
m_pipelineEngine = std::make_unique<softbus::message_bus::pipeline::PipelineEngine>(4096);
}
if (!m_pluginManager) {
m_pluginManager = std::make_shared<softbus::core::plugin_system::PluginManager>();
}
if (!m_pluginHost) {
m_pluginHost = std::make_unique<softbus::core::plugin_system::PluginHost>(m_pluginManager);
}
const auto pluginsObj = rootConfig.value(QStringLiteral("plugins")).toObject();
QSet<QString> loadedPluginPaths;
auto loadPlugins = [&](const QJsonArray& arr, const char* sourceTag) {
for (const auto& v : arr) {
const auto obj = v.toObject();
const QString path = obj.value(QStringLiteral("path")).toString();
if (path.isEmpty() || loadedPluginPaths.contains(path)) {
continue;
}
QString err;
if (!m_pluginHost->loadPlugin(path, &err)) {
LOG_WARNING() << "DeviceBusManager: plugin load failed source=" << sourceTag
<< "path=" << path << "err=" << err;
continue;
}
loadedPluginPaths.insert(path);
}
};
// New generic entry for protocol plugins; each .so may export parser/framer/mapper factories.
loadPlugins(pluginsObj.value(QStringLiteral("protocols")).toArray(), "protocols");
// Backward compatibility: legacy key still supported.
loadPlugins(pluginsObj.value(QStringLiteral("framers")).toArray(), "framers");
if (m_pluginManager) {
const auto parserIds = m_pluginManager->registeredProtocolPluginIds();
const auto framerIds = m_pluginManager->registeredProtocolFramerPluginIds();
const auto mapperIds = m_pluginManager->registeredProtocolMapperPluginIds();
LOG_INFO() << "DeviceBusManager: registered parser plugins(" << parserIds.size()
<< "):" << parserIds.join(QStringLiteral(", "));
LOG_INFO() << "DeviceBusManager: registered framer plugins(" << framerIds.size()
<< "):" << framerIds.join(QStringLiteral(", "));
LOG_INFO() << "DeviceBusManager: registered mapper plugins(" << mapperIds.size()
<< "):" << mapperIds.join(QStringLiteral(", "));
}
if (m_pipelineEngine) {
m_pipelineEngine->setMemoryPool(m_memoryPool);
m_pipelineEngine->loadRuntimeConfigFromJson(rootConfig.value(QStringLiteral("pipeline")).toObject());
m_pipelineEngine->setPluginManager(m_pluginManager);
ensureCoreConfigFilesInitialized();
loadDynamicRulesFromDedicatedConfig();
loadRuntimeMappingsFromDedicatedConfig();
loadProfileCatalogSingleton();
m_pipelineEngine->start();
}
if (!m_ingressAdapter) {
m_ingressAdapter = std::make_unique<softbus::message_bus::ingress::DriverIngressAdapter>(
m_memoryPool, m_pipelineEngine.get());
}
if (!m_egressRouter) {
m_egressRouter = std::make_unique<softbus::message_bus::egress::EgressRouter>();
}
if (!m_egressRunning.exchange(true)) {
m_egressThread = std::thread([this]() { this->processEgressLoop(); });
}
if (!m_treeModel) {
m_treeModel = std::make_shared<DeviceTreeModel>();
}
// 加载设备树
QString treeError;
if (!m_treeModel->loadFromDaemonConfig(rootConfig, &treeError)) {
LOG_ERROR() << "DeviceBusManager: failed to load device_tree:" << treeError;
return false;
}
const auto nodes = m_treeModel->nodes();
for (const auto& n : nodes) {
if (!n.enabled) 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) {
initializeSerialDevice(n.endpoint, n.params);
m_deviceEndpointsMap.insert(n.endpoint, kind);
} else {
LOG_WARNING() << "DeviceBusManager: skip unsupported kind for endpoint=" << n.endpoint
<< "type=" << n.type;
}
}
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_serialDevicesByEndpointSharedPtr.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_serialDevicesByEndpointSharedPtr.keys();
for (const auto& endpoint : currentKeys) {
if (!desiredSerialEndpoints.contains(endpoint)) {
shutdownSerialDevice(endpoint);
m_deviceEndpointsMap.remove(endpoint);
}
}
return true;
}
void DeviceBusManager::shutdown()
{
m_egressRunning.store(false);
if (m_egressThread.joinable()) {
m_egressThread.join();
}
// 关闭并销毁所有串口设备
const auto keys = m_serialDevicesByEndpointSharedPtr.keys();
for (const auto& endpoint : keys) {
shutdownSerialDevice(endpoint);
}
if (m_pipelineEngine) {
m_pipelineEngine->stop();
m_pipelineEngine->drain();
}
}
std::vector<softbus::devices::DeviceInfo> DeviceBusManager::listDevices() const
{
if (!m_registry) {
return {};
}
return m_registry->listDevices();
}
std::optional<softbus::devices::DeviceInfo> DeviceBusManager::findDeviceById(int id) const
{
if (!m_registry) {
return std::nullopt;
}
return m_registry->findById(id);
}
softbus::message_bus::pipeline::PipelineEngine* DeviceBusManager::pipelineEngine() const
{
return m_pipelineEngine.get();
}
std::shared_ptr<softbus::core::plugin_system::PluginManager> DeviceBusManager::pluginManager() const
{
return m_pluginManager;
}
void DeviceBusManager::initializeSerialDevice(const QString& endpoint, const QJsonObject& params)
{
softbus::device_bus::manager::SerialInitDeps deps;
deps.treeModel = m_treeModel.get();
deps.dirtyCb = m_dirtyCb;
deps.registry = m_registry;
deps.ingressAdapter = m_ingressAdapter.get();
deps.memoryPool = m_memoryPool;
deps.egressRouter = m_egressRouter.get();
deps.serialDevicesByEndpoint = &m_serialDevicesByEndpointSharedPtr;
(void)softbus::device_bus::manager::initializeSerialDeviceWithDeps(endpoint, params, deps);
}
void DeviceBusManager::shutdownSerialDevice(const QString& endpoint)
{
auto it = m_serialDevicesByEndpointSharedPtr.find(endpoint);
if (it == m_serialDevicesByEndpointSharedPtr.end()) {
return;
}
auto device = it.value();
if (device) {
auto info = device->deviceInfo();
if (m_registry && info.id >= 0) {
m_registry->unregisterDevice(info.id);
}
device->stop();
}
if (m_egressRouter) {
m_egressRouter->unbindSerialDevice(endpoint);
}
m_serialDevicesByEndpointSharedPtr.erase(it);
}
void DeviceBusManager::processEgressLoop()
{
while (m_egressRunning.load()) {
if (!m_pipelineEngine || !m_egressRouter) {
std::this_thread::sleep_for(std::chrono::milliseconds(2));
continue;
}
softbus::core::models::RawBusMessage out;
if (!m_pipelineEngine->tryPopEgress(out)) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
const bool ok = m_egressRouter->send(out);
if (!ok) {
// LOG_WARNING() << "DeviceBusManager: egress send failed endpoint=" << out.endpoint;
}
}
}