5 // Created by Mitch Adler on 11/2/16.
9 #import <Foundation/Foundation.h>
11 #import "CKDAKSLockMonitor.h"
13 #include <utilities/SecCFRelease.h>
14 #include <utilities/SecAKSWrappers.h>
15 #include <utilities/debugging.h>
19 @interface CKDAKSLockMonitor ()
21 @property XPCNotificationDispatcher* dispatcher;
22 @property XPCNotificationBlock notificationBlock;
23 @property dispatch_queue_t queue;
27 @implementation CKDAKSLockMonitor
29 + (instancetype) monitor {
30 return [[CKDAKSLockMonitor alloc] init];
33 - (instancetype)init {
37 XPCNotificationDispatcher* dispatcher = [XPCNotificationDispatcher dispatcher];
39 _queue = dispatch_queue_create("CKDAKSLockMonitor", NULL);
41 _unlockedSinceBoot = false;
43 /* also use dispatch to make sure */
45 __weak typeof(self) weakSelf = self;
46 notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int t) {
47 [weakSelf _onqueueRecheck];
52 [dispatcher addListener: self];
58 - (void) handleNotification:(const char *)name {
59 if (strcmp(name, kUserKeybagStateChangeNotification) == 0 || strcmp(name, "com.apple.mobile.keybagd.lock_status") == 0) {
64 - (void) notifyListener {
65 // Take a strong reference:
66 __strong __typeof(self.listener) listener = self.listener;
77 - (void)connectTo: (NSObject<CKDLockListener>*) listener {
79 [self notifyListener];
83 dispatch_async(_queue, ^{
84 [self _onqueueRecheck];
88 - (void) _onqueueRecheck {
89 CFErrorRef aksError = NULL;
90 bool locked = true; // Assume locked if we get an error
92 if (!SecAKSGetIsLocked(&locked, &aksError)) {
93 secerror("%@ Got error querying lock state: %@", self, aksError);
94 CFReleaseSafe(aksError);
97 BOOL previousLocked = self.locked;
101 _unlockedSinceBoot = true;
104 if (previousLocked != self.locked) {
105 // recheck might get called from ckdkvsproxy_queue (see 30510390)
106 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
107 [self notifyListener];