I'm trying to read the current kPMSetClamshellSleepState setting from my launch daemon for macOS. I tried the following approach:
io_connect_t connection = IO_OBJECT_NULL;
io_service_t pmRootDomain = IOServiceGetMatchingService(kIOMainPortDefault,
IOServiceMatching("IOPMrootDomain"));
if(pmRootDomain)
{
kern_return_t res = IOServiceOpen(pmRootDomain, current_task(), 0, &connection);
if(res == KERN_SUCCESS)
{
uint64_t outputs[1] = { };
uint32_t num_outputs = 1;
res = IOConnectCallScalarMethod(connection,
kPMSetClamshellSleepState,
NULL,
0,
outputs,
&num_outputs);
if(res == KERN_SUCCESS)
{
//Done
}
//Close connection
IOServiceClose(connection);
}
IOObjectRelease(pmRootDomain);
}
But in this case the call to IOConnectCallScalarMethod returns 0xE00002C2, or -536870206, or kIOReturnBadArgument.
How do I read a setting? Any advice.
I/O Kit User Client External Methods
There are no generalised semantics you can infer about an I/O Kit user client's external method API and what combination of scalar and struct inputs or outputs you may pass to it. This always depends on the specific
IOUserClientsubclass with which you're interfacing, and the specific method selector you're passing.In your case, you're dealing with
RootDomainUserClientand selectorkPMSetClamshellSleepState, whose allowed arguments are defined here:So, you can only call this selector with precisely 1 scalar input and no other arguments. Moreover, its return value does not depend on previous state. There's no way of hacking this specific interface to do what you want.
Clamshell state
If you trace the external method through, you'll find the state stored in the
IOPMRootDomainobject'sclamshellSleepDisableMaskfield. I don't see a direct user space accessor for this.It is referenced in the
IOPMrootDomain::shouldSleepOnClamshellClosed()function, whose state is reflected in thekAppleClamshellCausesSleepKey/"AppleClamshellCausesSleep"property. You can query this property usingIORegistryEntryCreateCFPropertyfrom user space.The exact value of the exposed property also depends on a bunch of other flags:
true,clamshellSleepDisableMaskmust befalsefalsefor other reasons thanclamshellSleepDisableMaskbeingtrueSo you will not be able to infer
clamshellSleepDisableMaskwith 100% accuracy from this property alone, but perhaps it's enough. You can also pick up the trail through theIOPMRootDomainsource code where I left off, perhaps there's another place where you can infer something about the state of this flag. Of note, there's thekIOPMMessageClamshellStateChangemessage which is apparently delivered to listeners when the above value is updated - perhaps responding to changes like this leads you to a reliable solution.