1 #import <TargetConditionals.h>
2 #import <Foundation/Foundation.h>
3 #import <Security/SecXPCHelper.h>
6 #import <NanoRegistry/NanoRegistry.h>
7 #import <xpc/private.h>
8 #endif /* TARGET_OS_WATCH */
10 #import "OTPairingService.h"
11 #import "OTPairingConstants.h"
14 static void create_xpc_listener(xpc_handler_t handler);
15 static bool should_retry(NSError *error);
16 static void pairing_retry_register(bool checkin);
17 static void pairing_retry_unregister(void);
18 #endif /* TARGET_OS_WATCH */
23 static OTPairingService *service;
26 service = [OTPairingService sharedService];
30 /* Check in; handle a possibly-pending retry. */
31 pairing_retry_register(true);
33 create_xpc_listener(^(xpc_object_t message) {
36 reply = xpc_dictionary_create_reply(message);
38 /* Received an explicit pairing request; remove retry activity if one exists. */
39 pairing_retry_unregister();
41 [service initiatePairingWithCompletion:^(bool success, NSError *error) {
42 xpc_connection_t connection;
45 os_log(OS_LOG_DEFAULT, "xpc-initiated pairing succeeded");
47 os_log(OS_LOG_DEFAULT, "xpc-initiated pairing failed: %@", error);
50 xpc_dictionary_set_bool(reply, OTPairingXPCKeySuccess, success);
52 NSData *errdata = [SecXPCHelper encodedDataFromError:error];
53 xpc_dictionary_set_data(reply, OTPairingXPCKeyError, errdata.bytes, errdata.length);
55 connection = xpc_dictionary_get_remote_connection(reply);
56 xpc_connection_send_message(connection, reply);
58 // Retry on failure - unless we were already in
59 if (!success && should_retry(error)) {
60 pairing_retry_register(false);
64 #endif /* TARGET_OS_WATCH */
71 create_xpc_listener(xpc_handler_t handler)
73 static xpc_connection_t listener;
75 listener = xpc_connection_create_mach_service(OTPairingMachServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
76 xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
77 if (xpc_get_type(peer) != XPC_TYPE_CONNECTION) {
81 // TODO: entitlement check
83 xpc_connection_set_event_handler(peer, ^(xpc_object_t message) {
84 if (xpc_get_type(message) != XPC_TYPE_DICTIONARY) {
88 char *desc = xpc_copy_description(message);
89 os_log(OS_LOG_DEFAULT, "received xpc message: %s", desc);
96 xpc_connection_activate(peer);
98 xpc_connection_activate(listener);
102 should_retry(NSError *error)
106 if ([error.domain isEqualToString:OTPairingErrorDomain]) {
107 switch (error.code) {
108 case OTPairingErrorTypeAlreadyIn:
109 case OTPairingErrorTypeBusy:
124 pairing_retry_register(bool checkin)
126 xpc_object_t criteria;
129 criteria = XPC_ACTIVITY_CHECK_IN;
131 os_log(OS_LOG_DEFAULT, "scheduling pairing retry");
133 pairing_retry_unregister();
135 criteria = xpc_dictionary_create(NULL, NULL, 0);
136 xpc_dictionary_set_string(criteria, XPC_ACTIVITY_PRIORITY, XPC_ACTIVITY_PRIORITY_MAINTENANCE);
137 xpc_dictionary_set_int64(criteria, XPC_ACTIVITY_INTERVAL, OTPairingXPCActivityInterval);
138 xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_REPEATING, true);
139 xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_ALLOW_BATTERY, true);
140 xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_REQUIRES_CLASS_A, true);
141 xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_COMMUNICATES_WITH_PAIRED_DEVICE, true);
144 xpc_activity_register(OTPairingXPCActivityIdentifier, criteria, ^(xpc_activity_t activity) {
145 xpc_activity_state_t state = xpc_activity_get_state(activity);
146 if (state == XPC_ACTIVITY_STATE_RUN) {
147 os_log(OS_LOG_DEFAULT, "triggered pairing attempt via XPC Activity");
148 OTPairingService *service = [OTPairingService sharedService];
149 [service initiatePairingWithCompletion:^(bool success, NSError *error) {
151 os_log(OS_LOG_DEFAULT, "Pairing retry succeeded");
152 pairing_retry_unregister();
154 os_log(OS_LOG_DEFAULT, "Pairing retry failed: %@", error);
155 // Activity repeats...
163 pairing_retry_unregister(void)
165 xpc_activity_unregister(OTPairingXPCActivityIdentifier);
167 #endif /* TARGET_OS_WATCH */