#include <asl.h>
#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
#include <libproc.h>
#include <bsm/libbsm.h>
#include "HIDEventWatcher.h"
static CFMutableArrayRef gHIDEventHistory = NULL;
static const CFTimeInterval kFiveMinutesInSeconds = (double)300.0;
static const int kMaxFiveMinutesWindowsCount = 12;
#define __NX_NULL_EVENT 0
__private_extern__ kern_return_t _io_pm_hid_event_report_activity(
mach_port_t server,
audit_token_t token,
int _action)
{
pid_t callerPID;
CFNumberRef appPID = NULL;
int _app_pid_;
CFMutableDictionaryRef foundDictionary = NULL;
CFMutableArrayRef bucketsArray = NULL;
CFDataRef dataEvent = NULL;
IOPMHIDPostEventActivityWindow *ev = NULL;
CFAbsoluteTime timeNow = CFAbsoluteTimeGetCurrent();
int arrayCount = 0;
int i = 0;
if (!gHIDEventHistory) {
gHIDEventHistory = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks);
}
if (!gHIDEventHistory) {
goto exit;
}
audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL);
if (0 !=(arrayCount = CFArrayGetCount(gHIDEventHistory)))
{
for (i=0; i<arrayCount; i++)
{
CFMutableDictionaryRef dictionaryForApp = NULL;
dictionaryForApp = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(gHIDEventHistory, i);
if (!dictionaryForApp) {
break;
}
appPID = CFDictionaryGetValue(dictionaryForApp, kIOPMHIDAppPIDKey);
if (appPID) {
CFNumberGetValue(appPID, kCFNumberIntType, &_app_pid_);
if (callerPID == _app_pid_) {
foundDictionary = dictionaryForApp;
break;
}
}
}
}
if (!foundDictionary) {
foundDictionary = CFDictionaryCreateMutable(0, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFArrayAppendValue(gHIDEventHistory, foundDictionary);
CFRelease(foundDictionary);
appPID = CFNumberCreate(0, kCFNumberIntType, &callerPID);
if (appPID) {
CFDictionarySetValue(foundDictionary, kIOPMHIDAppPIDKey, appPID);
CFRelease(appPID);
}
CFStringRef appName = NULL;
char appBuf[MAXPATHLEN];
int len = proc_name(callerPID, appBuf, MAXPATHLEN);
if (0 != len) {
appName = CFStringCreateWithCString(0, appBuf, kCFStringEncodingMacRoman);
if (appName) {
CFDictionarySetValue(foundDictionary, kIOPMHIDAppPathKey, appName);
CFRelease(appName);
}
}
}
if (!foundDictionary)
goto exit;
bucketsArray = (CFMutableArrayRef)CFDictionaryGetValue(foundDictionary, kIOPMHIDHistoryArrayKey);
if (!bucketsArray) {
bucketsArray = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks);
CFDictionarySetValue(foundDictionary, kIOPMHIDHistoryArrayKey, bucketsArray);
CFRelease(bucketsArray);
}
if (!bucketsArray)
goto exit;
bool foundWindowForEvent = false;
if (0 < CFArrayGetCount(bucketsArray)) {
dataEvent = (CFDataRef)CFArrayGetValueAtIndex(bucketsArray, 0);
}
if (dataEvent) {
ev = (IOPMHIDPostEventActivityWindow *)CFDataGetBytePtr(dataEvent);
if (timeNow < (ev->eventWindowStart + kFiveMinutesInSeconds))
{
if (__NX_NULL_EVENT == _action) {
ev->nullEventCount++;
} else {
ev->hidEventCount++;
}
foundWindowForEvent = true;
}
}
if (!foundWindowForEvent) {
IOPMHIDPostEventActivityWindow newv;
newv.eventWindowStart = ((int)timeNow / (int)kFiveMinutesInSeconds) * kFiveMinutesInSeconds;
newv.nullEventCount = newv.hidEventCount = 0;
if (__NX_NULL_EVENT == _action) {
newv.nullEventCount++;
} else {
newv.hidEventCount++;
}
dataEvent = CFDataCreate(0, (const UInt8 *)&newv, sizeof(IOPMHIDPostEventActivityWindow));
if (dataEvent) {
CFArrayInsertValueAtIndex(bucketsArray, 0, dataEvent);
CFRelease(dataEvent);
}
while (kMaxFiveMinutesWindowsCount < CFArrayGetCount(bucketsArray)) {
CFArrayRemoveValueAtIndex(bucketsArray, CFArrayGetCount(bucketsArray) - 1);
}
}
exit:
return KERN_SUCCESS;
}
__private_extern__ kern_return_t _io_pm_hid_event_copy_history(
mach_port_t server,
vm_offset_t *array_data,
mach_msg_type_number_t *array_dataLen,
int *return_val)
{
CFDataRef sendData = NULL;
sendData = CFPropertyListCreateData(0, gHIDEventHistory, kCFPropertyListXMLFormat_v1_0, 0, NULL);
if (!sendData) {
*return_val = kIOReturnError;
goto exit;
}
*array_data = (vm_offset_t)CFDataGetBytePtr(sendData);
*array_dataLen = (size_t)CFDataGetLength(sendData);
vm_allocate(mach_task_self(), (vm_address_t *)array_data, *array_dataLen, TRUE);
if (*array_data) {
memcpy((void *)*array_data, CFDataGetBytePtr(sendData), *array_dataLen);
*return_val = kIOReturnSuccess;
}
CFRelease(sendData);
*return_val = kIOReturnSuccess;
exit:
return KERN_SUCCESS;
}