订阅属性变化无法正常获取通知

问题描述

参考新增组件,对资源协作接口的属性进行订阅,已参考基于资源协作接口的订阅机制指导 | 文档中心 | openUBMC 该文档,但是始终无法获取属性变化通知,请问是什么原因?

定位过程

service.json文件新增

{
    "name": "my_app",
    "type": "application",
    "deployConfig": "",
    "version": "0.0.1",
    "user": "test",
    "license": "",
    "codegen_policy": {
        "version": "18"
    },
    "description": "",
    "dependencies": {
        "test": [
        ],
        "build": [
            {
                "conan": "libmc4lua/[>=0.0.1]"
            },
            {
                "conan": "mdb_interface/[>=0.0.1]"
            }
        ]
    },
    "required": [
        {
            "path": "/bmc/kepler/Systems/${SystemId}/FruCtrl/${Id}",
            "interface": "bmc.kepler.Systems.FruCtrl",
            "properties": {
                "PowerState": ["subscribe"]
            }
        }
    ]
}

通过bmcgo gen 自动生成代码,client.lua 中已有对应的接口

function my_app_client:OnFruCtrlPropertiesChanged(cb, path_params)
    local path_namespace = path_params and
                               ('/bmc/kepler/Systems/' .. path_params['SystemId'] .. '/FruCtrl/' .. path_params['Id']) or
                               '/bmc/kepler/Systems/:SystemId/FruCtrl/:Id'
    self.signal_slots[#self.signal_slots + 1] = subscribe_signal.on_properties_changed(self:get_bus(), path_namespace,
        cb, 'bmc.kepler.Systems.FruCtrl', {'PowerState'})
end

my_app_app.lua中代码如下

local class = require 'mc.class'
local service = require 'my_app.service'
local my_app_client = require 'my_app.client'
local logging = require 'mc.logging'

local my_app = class(service)

function my_app:ctor()

end

function my_app:init()
    self.super.init(self)

    logging:notice("my_app init")

    my_app_client:OnFruCtrlPropertiesChanged(function(values, path)
        if values['PowerState'] then
            logging:notice("power state change")
        end
        local system_id = tonumber(string.match(path or '', '/bmc/kepler/Systems/(%d+)/FruCtrl'))
            logging:notice("OnFruCtrlPropertiesChanged state system_id %d", system_id)
    end)

    logging:notice("my_app init end")
    
end

return my_app

mdbctl setprop 设置PowerState属性,通过busctl --user monitor bmc.kepler.fructrl 能监听对应的信号变化,
my_app init和my_app init end都有打印,但是power state change未有打印,情况与订阅属性变化信号无法正常捕获到 初始一致,但是未能从文档中分析出来哪里存在差异,导致订阅属性变更失败,请问是以上哪里存在问题?还是需要其他进行配置?

环境信息

  • 软件版本:[如 OpenUBMC2509]

重现步骤

答案内容由AI生成,仅供参考:
根据您提供的详细问题描述、代码以及上下文信息,问题的核心原因很可能在于您订阅的属性 PowerState 在定义时,其 emitsChangedSignal 属性被设置为了 falseconstinvalidates,导致即使属性值发生了变化,D-Bus 上也没有发出携带属性值的 PropertiesChanged 信号,您的回调函数自然无法被触发。

以下是基于上下文信息的具体分析和相应的排查与解决方案:

1. 根本原因分析:emitsChangedSignal 属性配置不当

  • 关键证据:在您提供的 基于资源协作接口的订阅机制指导 文档片段中明确指出:

    emitsChangedSignal 表示是否发送属性变化信号,默认为 "true"

    • 如果取值为 false,表示属性变化时不发送信号;
    • 如果取值为 const,表示属性永不变化,不需要发送信号;
    • 如果取值为 true,表示属性变化时发送信号,信号携带属性值;
    • 如果取值为 invalidates,表示属性变化时发送信号,但信号不携带属性值;
  • 问题关联:您提到 busctl --user monitor bmc.kepler.fructrl 能监听到信号变化,这说明 D-Bus 信号本身是在发送的。但您的回调函数 OnFruCtrlPropertiesChanged 是通过 subscribe_signal.on_properties_changed 实现的,它依赖的是标准的 org.freedesktop.DBus.Properties.PropertiesChanged 信号,并且该信号必须携带变化后的属性值

  • 结论:如果 PowerState 属性的定义中 "emitsChangedSignal" 被设置为 "invalidates"(只发信号不带值)或 "false"/"const"(完全不发信号),那么 subscribe_signal.on_properties_changed 机制将无法捕获到符合其预期的、携带值的信号,从而导致回调函数不被执行。您虽然通过 busctl 捕捉到了一些信号,但这些信号可能并非 PropertiesChanged,或者是 PropertiesChanged 但因 invalidates 选项而未包含 PowerState 值。

2. 排查步骤与解决方案

请按照以下步骤进行排查和修复:

步骤一:检查 FruCtrl.jsonPowerState 属性的定义

  • 操作:找到定义 FruCtrl 接口的 JSON 文件(根据您提供的代码,路径应为 mdb_interface 仓库下的 json/intf/mdb/bmc/kepler/Systems/FruCtrl.json 或其项目内的等效文件)。
  • 关键检查点:查找 PowerState 属性对应的定义,确认其 options 块中的 emitsChangedSignal 字段的取值。
  • 理想值:应为 "true"(或直接省略,因为默认值为 true)。
  • 问题值:如果发现是 "false""const""invalidates",请将其修改为 "true" 或直接删除该行。
    • 示例修复:
      "PowerState": {
          "type": "string",
          ...
          "options": {
              "emitsChangedSignal": "true" // <-- 确保为此值,或删除整段options
          }
      }
      

步骤二:验证 subscribe_signal.on_properties_changed 的返回值

  • 操作:在您的 my_app_client:OnFruCtrlPropertiesChanged 函数中,打印 subscribe_signal.on_properties_changed 的返回值,检查其是否为一个有效的标识符。
  • 代码示例(用于调试)
    function my_app_client:OnFruCtrlPropertiesChanged(cb, path_params)
        -- ... 路径构建逻辑 ...
        local slot_id = subscribe_signal.on_properties_changed(self:get_bus(), path_namespace,
            cb, 'bmc.kepler.Systems.FruCtrl', {'PowerState'})
        print("subscription slot id: " .. tostring(slot_id)) -- 检查是否成功返回了标识符
        self.signal_slots[#self.signal_slots + 1] = slot_id
        -- 注:为简单起见,这里直接使用了 print,实际应使用 logging
    end
    
  • 预期结果:应打印出类似 subscription slot id: 1 的信息。如果返回 nil,则说明订阅本身可能就失败了。

步骤三:检查回调函数签名

  • 操作:确认您的回调函数签名是否与 subscribe_signal.on_properties_changed 的预期一致。
  • 预期签名function(changed_properties, path)
    • changed_properties:是一个table,包含所有变化了的属性及其新值。
    • path:是发生变化的对象的 D-Bus 路径。
  • 您的代码检查:您的回调函数中使用了 if values['PowerState'] then ... end,这是正确的。但请确认 values 参数确实是被传入的 changed_properties table。

步骤四:确认 my_app 服务已正确启动并连接到 D-Bus

  • 操作:确保 my_app 应用在 systemd 或类似进程管理器中正常启动,并且其 user 字段(您设置的是 test)具有访问目标 D-Bus 接口的权限。
  • 日志检查:查看系统日志(如 journalctl -u my_app),确认 my_app initmy_app init end 日志打印正常,并且没有其他错误日志(如连接失败、权限拒绝等)。
  • 特别注意:您的问题标题提到了“新增对象不上树问题分析”,其中提到了由于 systemd 配置文件未裁剪导致重复的进程拉起。请务必检查您的服务是否被重复启动了,这可能导致 D-Bus 注册异常,从而影响信号订阅。

步骤五:参考官方示例和最佳实践

  • 再次详细阅读您提到的 基于资源协作接口的订阅机制指导 文档。
  • 重点核对文档中关于 required 字段定义的格式。您的 service.jsonrequired 字段的定义看起来是正确的,但请务必确认 properties 子项的格式完全匹配文档要求。

总结排查清单

排查项 预期结果 您的现状 建议操作
1. emitsChangedSignal 应为 true 或不存在(默认) 可能为 false/const/invalidates 立即检查并修改
2. 订阅返回值 应为一个非 nil 的标识符 未知 添加日志打印确认
3. 回调函数签名 function(table, string) 您已使用正确 确认参数是否按预期传递
4. 服务状态与权限 正常运行,无重复进程,D-Bus连接正常 未知 检查系统日志和进程状态
5. service.json格式 严格匹配文档规范 您的写法看起来正确 逐字比对文档示例

最可能的解决方案:请您优先检查并修正目标属性 PowerState 在接口定义文件中的 emitsChangedSignal 配置。将问题属性的该配置设置为 true 后,重新部署并测试,很大概率能解决您的问题。

感觉有可能是你这个组件启动比较快,fructrl的接口还未注册上树,所以订阅失败