Skip to content

Instantly share code, notes, and snippets.

@uucidl
Last active May 27, 2020 22:46
Show Gist options
  • Save uucidl/a707852ff57f68ddab990b2676a87ce5 to your computer and use it in GitHub Desktop.
Save uucidl/a707852ff57f68ddab990b2676a87ce5 to your computer and use it in GitHub Desktop.
IOKit

The IOKit framework is Apple’s base framework to interact with devices. This is your go to when for instance working with USB devices.

There is a way in IOKit to register notifications to discover devices as they are plugged by our users. The API seems easy enough (see IOKitLib header)

However I was puzzled for quite long why my notifications were not processed. It turns out you have to process the iterator immediately after calling IOServiceAddMatchingNotification, otherwise notifications won’t be pulled.

This is said in the fine line of the IOKitLib.h header file as:

/*! @function IOServiceAddMatchingNotification
 * ...
 * @param notification An iterator handle is returned on success, and should be released
 * by the caller when the notification is to be destroyed. The notification is armed when
 * the iterator is emptied by calls to IOIteratorNext - when no more objects are returned,
 * the notification is armed. Note the notification is not armed when first created.
 */
  1. The notification is not armed when first created
  2. It is armed when the notification is emptied by calls to IOIteratorNext
  3. If it is not armed, then your callback will never be called

Therefore here is the sequence of calls we would almost always use:

// Install watcher for new IOKit devices.
//
// `matchingDictSink` gets consumed and deallocated.
// `callback` gets called on already existing matching devices and all newly published matching
// devices
// `result_iterator` must be kept alive and will contain results for notifications
static kern_return_t
watch_new_matching_devices (IONotificationPortRef notification_port,
                            CFMutableDictionaryRef matching_dict_sink,
                            IO_SERVICE_MATCHING_CALLBACK (callback),
                            void* refCon,
                            io_iterator_t* result_iterator)
{
	kern_return_t kr;
	kr = IOServiceAddMatchingNotification (
	notification_port, kIOFirstMatchNotification, matching_dict_sink, callback, refCon, result_iterator);
	if (kr != KERN_SUCCESS) {
		return kr;
	}
	// NOTE(nicolas): you MUST call the function after
	// IOServiceAddMatchingNotification is called, because
	// if you don't pull from the iterator somehow the
	// notifications will get stuck and won't be pulled at
	// all later on.
	callback (refCon, *result_iterator);
	return kr;
}
@PratikKankriya
Copy link

PratikKankriya commented Sep 7, 2018

We are using iOKit framework for fetching battery info for finding battery wear but on iOS 12 beta we are not able to fetch current capacity & voltage please tell us any alternative framework or how to resolve this issue

Following is the code use :
NSMutableString *allInfo = [NSMutableString new];

CFTypeRef blob = IOPSCopyPowerSourcesInfo();
CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
if (CFArrayGetCount(sources) == 0)
    return;	// Could not retrieve battery information.  System may not have a battery.

NSDictionary *limitedBatteryInfo = ((NSDictionary*)((NSArray*)CFBridgingRelease(blob))[0]);

[allInfo appendString:@"IOPSCopyPowerSourcesInfo Data\n\n"];

for (NSString* dictKey in [limitedBatteryInfo allKeys]) {
    [allInfo appendString:[NSString stringWithFormat:@"%@ : %@",dictKey,[limitedBatteryInfo valueForKey:dictKey]]];
    [allInfo appendString:@"\n"];
}

io_service_t powerSource = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMPowerSource"));



CFMutableDictionaryRef batteryProperties = NULL;

IORegistryEntryCreateCFProperties(powerSource, &batteryProperties, NULL, 0);

NSDictionary *extensiveBatteryInfo = (__bridge_transfer NSDictionary *)batteryProperties;


[allInfo appendString:@"\n\n\nIOPMPowerSource Data\n\n"];

for (NSString* dictKey in [extensiveBatteryInfo allKeys]) {
    [allInfo appendString:[NSString stringWithFormat:@"%@ : %@",dictKey,[extensiveBatteryInfo valueForKey:dictKey]]];
    [allInfo appendString:@"\n"];
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment