You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在IORegistry中注册键并在kext中响应其变更?

Kext开发:发布属性并响应变更失败的问题

我正在学习kext开发,尝试实现一个简单的“通用”kext,使其在IORegistry中发布一个键并响应该键的变更。该类通过IOService::registerPowerDriver完成注册并发布键。根据资料:

当用户空间应用设置驱动属性时,对应驱动对象的setProperties()方法会被调用,参数包含已设置的属性字典。

我按此实现了代码,但在IORegistryExplorer.app中修改该键时,完全没有触发IOService::setProperties的调用。

头文件代码

#define ENABLED_PROP_NAME "Enabled"

class GenericPower : public IOService
{
    OSDeclareDefaultStructors(GenericPower);

public:
    virtual bool init(OSDictionary* dict) override;
    virtual IOService* probe(IOService* provider, SInt32* score) override;
    virtual void free(void) override;
    virtual bool start(IOService* provider) override;
    virtual void stop(IOService * provider) override;
    virtual IOReturn setProperties(OSObject* properties) override;

protected:

    virtual IOReturn        powerStateWillChangeTo(IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice) override;
    virtual IOReturn        setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice) override;
    virtual IOReturn        powerStateDidChangeTo(IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice) override;

    void updateProperties(void);

private:
    // Property to publish:
    bool isEnabled = true;
};

CPP文件代码

#define super IOService

OSDefineMetaClassAndStructors(GenericPower, super);

bool GenericPower::init(OSDictionary* dict)
{
    if (!super::init(dict)) {
        IOLog("GenericPower: init failed\n");
        return (false);
    }
    IOLog("GenericPower: init\n");

    return (true);
}

void GenericPower::free(void)
{
    IOLog("GenericPower: free\n");

    super::free();
}

IOService* GenericPower::probe(IOService* provider, SInt32* score)
{
    IOLog("GenericPower: probe\n");

    return (super::probe(provider, score));
}


IOReturn GenericPower::setProperties(OSObject* properties)
{
    IOLog("GenericPower: setProperties\n");

    if (properties == nullptr) {
        IOLog("GenericPower: setProperties: no properties\n");
        return (kIOReturnUnsupported);
    }

    OSDictionary* propertiesDict;
    propertiesDict = OSDynamicCast(OSDictionary, properties);
    if (propertiesDict == nullptr) {
        IOLog("GenericPower: setProperties: cannot get properties\n");
        return (kIOReturnUnsupported);
    }
    OSObject * rawValue = propertiesDict->getObject(ENABLED_PROP_NAME);
    OSBoolean * boolValue = OSDynamicCast(OSBoolean, rawValue);
    if (boolValue == nullptr) {
        IOLog("GenericPower: setProperties: cannot get \"" ENABLED_PROP_NAME "\" property\n");
    } else {
        IOLog("GenericPower: setProperties: new value %s\n", boolValue->getValue() ? "Enabled" : "Disabled");
        isEnabled = boolValue->getValue();
    }

    IOLog("GenericPower: setProperties: \"" ENABLED_PROP_NAME "\" set to %s\n", isEnabled ? "ON" : "OFF");

    updateProperties();

    return (kIOReturnSuccess);
}

enum {
    kPowerStateOff,
    kPowerStateSleep,
    kPowerStateOn,
//
    kNumPowerStates
};

static IOPMPowerState powerStates[kNumPowerStates] = {
    {
        // Off
        kIOPMPowerStateVersion1,          // version
        0,   // capabilityFlags
        0,                      // outputPowerCharacter
        0,                      // inputPowerRequirement
        0, 0, 0, 0, 0, 0, 0, 0
    },
    {
        // Sleep
        kIOPMPowerStateVersion1,          // version
        kIOPMSleepCapability,   // capabilityFlags
        kIOPMSleep,                      // outputPowerCharacter
        kIOPMSleep,                      // inputPowerRequirement
        0, 0, 0, 0, 0, 0, 0, 0
    },
    {
        // On
        kIOPMPowerStateVersion1,          // version
        kIOPMPowerOn | kIOPMDeviceUsable,   // capabilityFlags
        kIOPMPowerOn,                      // outputPowerCharacter
        kIOPMPowerOn,                      // inputPowerRequirement
        0, 0, 0, 0, 0, 0, 0, 0
    },
};

bool GenericPower::start(IOService* provider)
{
    if (!super::start(provider)) {
        IOLog("GenericPower: start: IOService start error\n");
        return (false);
    }

    PMinit();
    provider->joinPMtree(this);
    registerPowerDriver(this, powerStates, kNumPowerStates);

    makeUsable();
    registerService();

    updateProperties();

    return (true);
}
void GenericPower::stop(IOService* provider)
{
    IOLog("GenericPower: stop. isEnabled=%d\n", (int)isEnabled);

    PMstop();
    super::stop(provider);
}

// /////////////////////////////////////////////////////////////

IOReturn GenericPower::powerStateWillChangeTo(IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice)
{
    IOLog("GenericPower: powerStateWillChangeTo %lu\n", stateNumber);
    return (kIOPMAckImplied);
}

IOReturn GenericPower::setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice)
{
    IOLog("GenericPower: setPowerState %lu\n", powerStateOrdinal);

    return (kIOPMAckImplied);
}

IOReturn GenericPower::powerStateDidChangeTo(IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice)
{
    IOLog("GenericPower: powerStateDidChangeTo %lu\n", stateNumber);
    return (kIOPMAckImplied);

}
void GenericPower::updateProperties(void)
{
    // Properties init
    OSBoolean * osProp = OSBoolean::withBoolean(isEnabled);
    setProperty(ENABLED_PROP_NAME, osProp);
    OSSafeReleaseNULL(osProp);
}

问题原因及解决方法

1. 权限问题

用户空间修改kext属性必须拥有root权限,IORegistryExplorer需要以sudo启动才能触发内核层的属性修改:

sudo /Applications/IORegistryExplorer.app/Contents/MacOS/IORegistryExplorer

2. 属性可写性验证

默认发布的属性可能未标记为可写,你可以在updateProperties方法中,通过IORegistryEntry::setProperty的扩展方式明确设置权限(如果需要),或者用命令行工具ioreg测试修改:

# 查找驱动节点并修改属性
sudo ioreg -w 0 -r -c GenericPower -d 1 -s Enabled -k Enabled -v -w true

3. 驱动节点挂载验证

确认IORegistryExplorer中能找到GenericPower节点,且该节点正确挂载到父设备下。如果驱动未正确匹配到设备,将无法接收属性修改消息,可检查Info.plist中IOKitPersonalities的IOProviderClass是否与父设备匹配。

4. setProperties方法覆盖确认

虽然代码中使用了override,但可在setProperties开头添加更醒目的日志(比如IOLog("=== setProperties triggered ===\n");),同时检查kext是否正确加载(用kextstat | grep GenericPower验证)。


内容的提问来源于stack exchange,提问作者BUKTOP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 00:53:09