#include "device_bus/manager/DeviceBusManager.h" #include #include #include #include #include #include #include #include #include // #include #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(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 model) { m_treeModel = std::move(model); } void DeviceBusManager::setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry) { m_registry = registry; } void DeviceBusManager::setDirtyCallback(std::function 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(4096, 4096); } if (!m_pipelineEngine) { m_pipelineEngine = std::make_unique(4096); } if (!m_pluginManager) { m_pluginManager = std::make_shared(); } if (!m_pluginHost) { m_pluginHost = std::make_unique(m_pluginManager); } const auto pluginsObj = rootConfig.value(QStringLiteral("plugins")).toObject(); QSet 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( m_memoryPool, m_pipelineEngine.get()); } if (!m_egressRouter) { m_egressRouter = std::make_unique(); } if (!m_egressRunning.exchange(true)) { m_egressThread = std::thread([this]() { this->processEgressLoop(); }); } if (!m_treeModel) { m_treeModel = std::make_shared(); } // 加载设备树 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 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 DeviceBusManager::listDevices() const { if (!m_registry) { return {}; } return m_registry->listDevices(); } std::optional 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 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; } } }