1 #if DEVELOPMENT || DEBUG
2 #include "TestIOServiceUserNotification.h"
3 #include <IOKit/IOService.h>
4 #include <IOKit/IOUserClient.h>
5 #include <IOKit/IOKitServer.h>
6 #include <kern/ipc_kobject.h>
7 #include "../../Kernel/IOServicePrivate.h"
8
9 OSDefineMetaClassAndStructors(TestIOServiceUserNotification, IOService);
10
11 OSDefineMetaClassAndStructors(TestIOServiceUserNotificationUserClient, IOUserClient);
12
13 bool
start(IOService * provider)14 TestIOServiceUserNotification::start(IOService * provider)
15 {
16 OSString * str = OSString::withCStringNoCopy("TestIOServiceUserNotificationUserClient");
17 bool ret = IOService::start(provider);
18 if (ret && str != NULL) {
19 setProperty(gIOUserClientClassKey, str);
20 fUserNotifications = OSArray::withCapacity(1);
21 fLock = IOLockAlloc();
22 registerService();
23 }
24 OSSafeReleaseNULL(str);
25 return ret;
26 }
27
28 void
free()29 TestIOServiceUserNotification::free()
30 {
31 if (fLock) {
32 IOLockFree(fLock);
33 fLock = NULL;
34 }
35 OSSafeReleaseNULL(fUserNotifications);
36 IOService::free();
37 }
38
39 void
registerUserNotification(OSObject * notification)40 TestIOServiceUserNotification::registerUserNotification(OSObject * notification)
41 {
42 IOLockLock(fLock);
43 // Proactively trim the list to avoid holding too many objects
44 trimUserNotificationsLocked();
45 assert(fUserNotifications->getNextIndexOfObject(notification, 0) == -1);
46 fUserNotifications->setObject(notification);
47 IOLockUnlock(fLock);
48 }
49
50 void
trimUserNotificationsLocked()51 TestIOServiceUserNotification::trimUserNotificationsLocked()
52 {
53 OSArray * remaining = OSArray::withCapacity(1);
54 if (!remaining) {
55 return;
56 }
57 fUserNotifications->iterateObjects(^(OSObject * obj) {
58 if (obj->getRetainCount() != 1) {
59 remaining->setObject(obj);
60 }
61 return false;
62 });
63 fUserNotifications->release();
64 fUserNotifications = remaining;
65 }
66
67 size_t
getUserNotificationLeakCount()68 TestIOServiceUserNotification::getUserNotificationLeakCount()
69 {
70 size_t count = 0;
71 IOLockLock(fLock);
72 trimUserNotificationsLocked();
73 count = fUserNotifications->getCount();
74 IOLockUnlock(fLock);
75 return count;
76 }
77
78 bool
start(IOService * provider)79 TestIOServiceUserNotificationUserClient::start(IOService * provider)
80 {
81 if (!IOUserClient::start(provider)) {
82 return false;
83 }
84 fProvider = OSDynamicCast(TestIOServiceUserNotification, provider);
85 assert(fProvider);
86 return true;
87 }
88
89 IONotifier *
registerInterest(const OSSymbol * typeOfInterest,IOServiceInterestHandler handler,void * target,void * ref)90 TestIOServiceUserNotificationUserClient::registerInterest(const OSSymbol * typeOfInterest,
91 IOServiceInterestHandler handler,
92 void * target,
93 void * ref)
94 {
95 IONotifier * notify = IOService::registerInterest(typeOfInterest, handler, target, ref);
96
97 // No straightforward way to make sure registerInterest is called from the test app
98 // Could check if handler is _ZN32IOServiceMessageUserNotification8_handlerEPvS0_jP9IOServiceS0_m
99 // But still cannot rule out other user process regisering interest
100 OSObject * obj = (OSObject *)target;
101 // Just panic the system if target isn't OSObject
102 fProvider->registerUserNotification(obj);
103
104 return notify;
105 }
106
107 IOReturn
clientClose()108 TestIOServiceUserNotificationUserClient::clientClose()
109 {
110 if (!isInactive()) {
111 terminate();
112 }
113 return kIOReturnSuccess;
114 }
115
116 IOReturn
externalMethod(uint32_t selector,IOExternalMethodArguments * args,IOExternalMethodDispatch * dispatch,OSObject * target,void * reference)117 TestIOServiceUserNotificationUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
118 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
119 {
120 if (selector == 0) {
121 registerService();
122 } else if (selector == 1 && args->scalarOutputCount >= 1) {
123 args->scalarOutput[0] = fProvider->getUserNotificationLeakCount();
124 }
125 return kIOReturnSuccess;
126 }
127
128 #endif /* DEVELOPMENT || DEBUG */
129