Add UI process watchdog on iOS to ensure WebProcess connections close
[WebKit-https.git] / Source / WebKit2 / Platform / IPC / mac / ConnectionMac.mm
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "Connection.h"
28
29 #include "DataReference.h"
30 #include "ImportanceAssertion.h"
31 #include "MachPort.h"
32 #include "MachUtilities.h"
33 #include <WebCore/AXObjectCache.h>
34 #include <mach/mach_error.h>
35 #include <mach/vm_map.h>
36 #include <wtf/RunLoop.h>
37 #include <xpc/xpc.h>
38
39 #if PLATFORM(IOS)
40 #include "ProcessAssertion.h"
41 #endif
42
43 #if __has_include(<xpc/private.h>)
44 #include <xpc/private.h>
45 #else
46 extern "C" void xpc_connection_get_audit_token(xpc_connection_t, audit_token_t*);
47 extern "C" void xpc_connection_kill(xpc_connection_t, int);
48 #endif
49
50 #if __has_include(<HIServices/AccessibilityPriv.h>)
51 #include <HIServices/AccessibilityPriv.h>
52 #else
53 typedef enum {
54     AXSuspendStatusRunning = 0,
55     AXSuspendStatusSuspended,
56 } AXSuspendStatus;
57 #endif
58
59 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
60 extern "C" AXError _AXUIElementNotifyProcessSuspendStatus(AXSuspendStatus);
61 #endif
62
63 namespace IPC {
64
65 static const size_t inlineMessageMaxSize = 4096;
66
67 // Message flags.
68 enum {
69     MessageBodyIsOutOfLine = 1 << 0
70 };
71     
72 // ConnectionTerminationWatchdog does two things:
73 // 1) It sets a watchdog timer to kill the peered process.
74 // 2) On iOS, make the process runnable for the duration of the watchdog
75 //    to ensure it has a chance to terminate cleanly.
76 class ConnectionTerminationWatchdog {
77 public:
78     static void createConnectionTerminationWatchdog(XPCPtr<xpc_connection_t>& xpcConnection, double intervalInSeconds)
79     {
80         new ConnectionTerminationWatchdog(xpcConnection, intervalInSeconds);
81     }
82     
83 private:
84     ConnectionTerminationWatchdog(XPCPtr<xpc_connection_t>& xpcConnection, double intervalInSeconds)
85         : m_xpcConnection(xpcConnection)
86         , m_watchdogTimer(RunLoop::main(), this, &ConnectionTerminationWatchdog::watchdogTimerFired)
87 #if PLATFORM(IOS)
88         , m_assertion(std::make_unique<WebKit::ProcessAssertion>(xpc_connection_get_pid(m_xpcConnection.get()), WebKit::AssertionState::Background))
89 #endif
90     {
91         m_watchdogTimer.startOneShot(intervalInSeconds);
92     }
93     
94     void watchdogTimerFired()
95     {
96         xpc_connection_kill(m_xpcConnection.get(), SIGKILL);
97         delete this;
98     }
99
100     XPCPtr<xpc_connection_t> m_xpcConnection;
101     RunLoop::Timer<ConnectionTerminationWatchdog> m_watchdogTimer;
102 #if PLATFORM(IOS)
103     std::unique_ptr<WebKit::ProcessAssertion> m_assertion;
104 #endif
105 };
106     
107 void Connection::platformInvalidate()
108 {
109     if (!m_isConnected)
110         return;
111
112     m_isConnected = false;
113
114     ASSERT(m_sendPort);
115     ASSERT(m_receivePort);
116
117     // Unregister our ports.
118     dispatch_source_cancel(m_deadNameSource);
119     dispatch_release(m_deadNameSource);
120     m_deadNameSource = 0;
121     m_sendPort = MACH_PORT_NULL;
122
123     dispatch_source_cancel(m_receivePortDataAvailableSource);
124     dispatch_release(m_receivePortDataAvailableSource);
125     m_receivePortDataAvailableSource = 0;
126     m_receivePort = MACH_PORT_NULL;
127
128 #if !PLATFORM(IOS)
129     if (m_exceptionPort) {
130         dispatch_source_cancel(m_exceptionPortDataAvailableSource);
131         dispatch_release(m_exceptionPortDataAvailableSource);
132         m_exceptionPortDataAvailableSource = 0;
133         m_exceptionPort = MACH_PORT_NULL;
134     }
135 #endif
136
137     m_xpcConnection = nullptr;
138 }
139     
140 void Connection::terminateSoon(double intervalInSeconds)
141 {
142     if (m_xpcConnection)
143         ConnectionTerminationWatchdog::createConnectionTerminationWatchdog(m_xpcConnection, intervalInSeconds);
144 }
145     
146 void Connection::platformInitialize(Identifier identifier)
147 {
148 #if !PLATFORM(IOS)
149     m_exceptionPort = MACH_PORT_NULL;
150     m_exceptionPortDataAvailableSource = nullptr;
151 #endif
152
153     if (m_isServer) {
154         m_receivePort = identifier.port;
155         m_sendPort = MACH_PORT_NULL;
156     } else {
157         m_receivePort = MACH_PORT_NULL;
158         m_sendPort = identifier.port;
159     }
160
161     m_deadNameSource = nullptr;
162     m_receivePortDataAvailableSource = nullptr;
163
164     m_xpcConnection = identifier.xpcConnection;
165 }
166
167 template<typename Function>
168 static dispatch_source_t createDataAvailableSource(mach_port_t receivePort, WorkQueue& workQueue, Function&& function)
169 {
170     dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, receivePort, 0, workQueue.dispatchQueue());
171     dispatch_source_set_event_handler(source, function);
172
173     dispatch_source_set_cancel_handler(source, ^{
174         mach_port_mod_refs(mach_task_self(), receivePort, MACH_PORT_RIGHT_RECEIVE, -1);
175     });
176
177     return source;
178 }
179
180 bool Connection::open()
181 {
182     if (m_isServer) {
183         ASSERT(m_receivePort);
184         ASSERT(!m_sendPort);
185         
186     } else {
187         ASSERT(!m_receivePort);
188         ASSERT(m_sendPort);
189
190         // Create the receive port.
191         mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_receivePort);
192
193 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
194         mach_port_set_attributes(mach_task_self(), m_receivePort, MACH_PORT_IMPORTANCE_RECEIVER, (mach_port_info_t)0, 0);
195 #endif
196
197         m_isConnected = true;
198         
199         // Send the initialize message, which contains a send right for the server to use.
200         auto encoder = std::make_unique<MessageEncoder>("IPC", "InitializeConnection", 0);
201         encoder->encode(MachPort(m_receivePort, MACH_MSG_TYPE_MAKE_SEND));
202
203         sendMessage(std::move(encoder));
204
205         initializeDeadNameSource();
206     }
207
208     // Change the message queue length for the receive port.
209     setMachPortQueueLength(m_receivePort, MACH_PORT_QLIMIT_LARGE);
210
211     // Register the data available handler.
212     RefPtr<Connection> connection(this);
213     m_receivePortDataAvailableSource = createDataAvailableSource(m_receivePort, *m_connectionQueue, [connection] {
214         connection->receiveSourceEventHandler();
215     });
216
217 #if !PLATFORM(IOS)
218     // If we have an exception port, register the data available handler and send over the port to the other end.
219     if (m_exceptionPort) {
220         m_exceptionPortDataAvailableSource = createDataAvailableSource(m_exceptionPort, *m_connectionQueue, [connection] {
221             connection->exceptionSourceEventHandler();
222         });
223
224         auto encoder = std::make_unique<MessageEncoder>("IPC", "SetExceptionPort", 0);
225         encoder->encode(MachPort(m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND));
226
227         sendMessage(std::move(encoder));
228     }
229 #endif
230
231     ref();
232     dispatch_async(m_connectionQueue->dispatchQueue(), ^{
233         dispatch_resume(m_receivePortDataAvailableSource);
234
235         if (m_deadNameSource)
236             dispatch_resume(m_deadNameSource);
237 #if !PLATFORM(IOS)
238         if (m_exceptionPortDataAvailableSource)
239             dispatch_resume(m_exceptionPortDataAvailableSource);
240 #endif
241
242         deref();
243     });
244
245     return true;
246 }
247
248 static inline size_t machMessageSize(size_t bodySize, size_t numberOfPortDescriptors = 0, size_t numberOfOOLMemoryDescriptors = 0)
249 {
250     size_t size = sizeof(mach_msg_header_t) + bodySize;
251     if (numberOfPortDescriptors || numberOfOOLMemoryDescriptors) {
252         size += sizeof(mach_msg_body_t);
253         if (numberOfPortDescriptors)
254             size += (numberOfPortDescriptors * sizeof(mach_msg_port_descriptor_t));
255         if (numberOfOOLMemoryDescriptors)
256             size += (numberOfOOLMemoryDescriptors * sizeof(mach_msg_ool_descriptor_t));
257     }
258     return round_msg(size);
259 }
260
261 bool Connection::platformCanSendOutgoingMessages() const
262 {
263     return true;
264 }
265
266 bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder)
267 {
268     Vector<Attachment> attachments = encoder->releaseAttachments();
269     
270     size_t numberOfPortDescriptors = 0;
271     size_t numberOfOOLMemoryDescriptors = 0;
272     for (size_t i = 0; i < attachments.size(); ++i) {
273         Attachment::Type type = attachments[i].type();
274         if (type == Attachment::MachPortType)
275             numberOfPortDescriptors++;
276     }
277     
278     size_t messageSize = machMessageSize(encoder->bufferSize(), numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
279
280     bool messageBodyIsOOL = false;
281     if (messageSize > inlineMessageMaxSize) {
282         messageBodyIsOOL = true;
283
284         numberOfOOLMemoryDescriptors++;
285         messageSize = machMessageSize(0, numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
286     }
287
288     char stackBuffer[inlineMessageMaxSize];
289     char* buffer = &stackBuffer[0];
290     if (messageSize > inlineMessageMaxSize)
291         buffer = (char*)mmap(0, messageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
292
293     bool isComplex = (numberOfPortDescriptors + numberOfOOLMemoryDescriptors > 0);
294
295     mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer);
296     header->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
297     header->msgh_size = messageSize;
298     header->msgh_remote_port = m_sendPort;
299     header->msgh_local_port = MACH_PORT_NULL;
300     header->msgh_id = 0;
301     if (messageBodyIsOOL)
302         header->msgh_id |= MessageBodyIsOutOfLine;
303
304     uint8_t* messageData;
305
306     if (isComplex) {
307         header->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
308
309         mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
310         body->msgh_descriptor_count = numberOfPortDescriptors + numberOfOOLMemoryDescriptors;
311         uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
312
313         for (size_t i = 0; i < attachments.size(); ++i) {
314             Attachment attachment = attachments[i];
315
316             mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
317             switch (attachment.type()) {
318             case Attachment::MachPortType:
319                 descriptor->port.name = attachment.port();
320                 descriptor->port.disposition = attachment.disposition();
321                 descriptor->port.type = MACH_MSG_PORT_DESCRIPTOR;            
322
323                 descriptorData += sizeof(mach_msg_port_descriptor_t);
324                 break;
325             default:
326                 ASSERT_NOT_REACHED();
327             }
328         }
329
330         if (messageBodyIsOOL) {
331             mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
332
333             descriptor->out_of_line.address = encoder->buffer();
334             descriptor->out_of_line.size = encoder->bufferSize();
335             descriptor->out_of_line.copy = MACH_MSG_VIRTUAL_COPY;
336             descriptor->out_of_line.deallocate = false;
337             descriptor->out_of_line.type = MACH_MSG_OOL_DESCRIPTOR;
338
339             descriptorData += sizeof(mach_msg_ool_descriptor_t);
340         }
341
342         messageData = descriptorData;
343     } else
344         messageData = (uint8_t*)(header + 1);
345
346     // Copy the data if it is not being sent out-of-line.
347     if (!messageBodyIsOOL)
348         memcpy(messageData, encoder->buffer(), encoder->bufferSize());
349
350     ASSERT(m_sendPort);
351
352     // Send the message.
353     kern_return_t kr = mach_msg(header, MACH_SEND_MSG, messageSize, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
354     if (kr != KERN_SUCCESS) {
355         // FIXME: What should we do here?
356     }
357
358     if (buffer != &stackBuffer[0])
359         munmap(buffer, messageSize);
360
361     return true;
362 }
363
364 void Connection::initializeDeadNameSource()
365 {
366     m_deadNameSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, m_sendPort, 0, m_connectionQueue->dispatchQueue());
367     dispatch_source_set_event_handler(m_deadNameSource, bind(&Connection::connectionDidClose, this));
368
369     mach_port_t sendPort = m_sendPort;
370     dispatch_source_set_cancel_handler(m_deadNameSource, ^{
371         // Release our send right.
372         mach_port_deallocate(mach_task_self(), sendPort);
373     });
374 }
375
376 static std::unique_ptr<MessageDecoder> createMessageDecoder(mach_msg_header_t* header)
377 {
378     if (!(header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
379         // We have a simple message.
380         uint8_t* body = reinterpret_cast<uint8_t*>(header + 1);
381         size_t bodySize = header->msgh_size - sizeof(mach_msg_header_t);
382
383         return std::make_unique<MessageDecoder>(DataReference(body, bodySize), Vector<Attachment>());
384     }
385
386     bool messageBodyIsOOL = header->msgh_id & MessageBodyIsOutOfLine;
387
388     mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
389     mach_msg_size_t numDescriptors = body->msgh_descriptor_count;
390     ASSERT(numDescriptors);
391
392     uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
393
394     // If the message body was sent out-of-line, don't treat the last descriptor
395     // as an attachment, since it is really the message body.
396     if (messageBodyIsOOL)
397         --numDescriptors;
398
399     // Build attachment list
400     Vector<Attachment> attachments(numDescriptors);
401
402     for (mach_msg_size_t i = 0; i < numDescriptors; ++i) {
403         mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
404
405         switch (descriptor->type.type) {
406         case MACH_MSG_PORT_DESCRIPTOR:
407             attachments[numDescriptors - i - 1] = Attachment(descriptor->port.name, descriptor->port.disposition);
408             descriptorData += sizeof(mach_msg_port_descriptor_t);
409             break;
410         default:
411             ASSERT(false && "Unhandled descriptor type");
412         }
413     }
414
415     if (messageBodyIsOOL) {
416         mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
417         ASSERT(descriptor->type.type == MACH_MSG_OOL_DESCRIPTOR);
418
419         uint8_t* messageBody = static_cast<uint8_t*>(descriptor->out_of_line.address);
420         size_t messageBodySize = descriptor->out_of_line.size;
421
422         auto decoder = std::make_unique<MessageDecoder>(DataReference(messageBody, messageBodySize), std::move(attachments));
423
424         vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(descriptor->out_of_line.address), descriptor->out_of_line.size);
425
426         return decoder;
427     }
428
429     uint8_t* messageBody = descriptorData;
430     size_t messageBodySize = header->msgh_size - (descriptorData - reinterpret_cast<uint8_t*>(header));
431
432     return std::make_unique<MessageDecoder>(DataReference(messageBody, messageBodySize), attachments);
433 }
434
435 // The receive buffer size should always include the maximum trailer size.
436 static const size_t receiveBufferSize = inlineMessageMaxSize + MAX_TRAILER_SIZE;
437 typedef Vector<char, receiveBufferSize> ReceiveBuffer;
438
439 static mach_msg_header_t* readFromMachPort(mach_port_t machPort, ReceiveBuffer& buffer)
440 {
441     buffer.resize(receiveBufferSize);
442
443     mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
444     kern_return_t kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
445     if (kr == MACH_RCV_TIMED_OUT)
446         return 0;
447
448     if (kr == MACH_RCV_TOO_LARGE) {
449         // The message was too large, resize the buffer and try again.
450         buffer.resize(header->msgh_size + MAX_TRAILER_SIZE);
451         header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
452         
453         kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
454         ASSERT(kr != MACH_RCV_TOO_LARGE);
455     }
456
457     if (kr != MACH_MSG_SUCCESS) {
458         ASSERT_NOT_REACHED();
459         return 0;
460     }
461
462     return header;
463 }
464
465 void Connection::receiveSourceEventHandler()
466 {
467     ReceiveBuffer buffer;
468
469     mach_msg_header_t* header = readFromMachPort(m_receivePort, buffer);
470     if (!header)
471         return;
472
473     std::unique_ptr<MessageDecoder> decoder = createMessageDecoder(header);
474     ASSERT(decoder);
475
476 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
477     decoder->setImportanceAssertion(std::make_unique<ImportanceAssertion>(header));
478 #endif
479
480     if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "InitializeConnection") {
481         ASSERT(m_isServer);
482         ASSERT(!m_isConnected);
483         ASSERT(!m_sendPort);
484
485         MachPort port;
486         if (!decoder->decode(port)) {
487             // FIXME: Disconnect.
488             return;
489         }
490
491         m_sendPort = port.port();
492         
493         if (m_sendPort) {
494             initializeDeadNameSource();
495             dispatch_resume(m_deadNameSource);
496         }
497
498         m_isConnected = true;
499
500         // Send any pending outgoing messages.
501         sendOutgoingMessages();
502         
503         return;
504     }
505
506 #if !PLATFORM(IOS)
507     if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "SetExceptionPort") {
508         if (m_isServer) {
509             // Server connections aren't supposed to have their exception ports overriden. Treat this as an invalid message.
510             m_clientRunLoop.dispatch(bind(&Connection::dispatchDidReceiveInvalidMessage, this, decoder->messageReceiverName().toString(), decoder->messageName().toString()));
511             return;
512         }
513         MachPort exceptionPort;
514         if (!decoder->decode(exceptionPort))
515             return;
516
517         setMachExceptionPort(exceptionPort.port());
518         return;
519     }
520 #endif
521
522     processIncomingMessage(std::move(decoder));
523 }    
524
525 #if !PLATFORM(IOS)
526 void Connection::exceptionSourceEventHandler()
527 {
528     ReceiveBuffer buffer;
529
530     mach_msg_header_t* header = readFromMachPort(m_exceptionPort, buffer);
531     if (!header)
532         return;
533
534     // We've read the exception message. Now send it on to the real exception port.
535
536     // The remote port should have a send once right.
537     ASSERT(MACH_MSGH_BITS_REMOTE(header->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE);
538
539     // Now get the real exception port.
540     mach_port_t exceptionPort = machExceptionPort();
541
542     // First, get the complex bit from the source message.
543     mach_msg_bits_t messageBits = header->msgh_bits & MACH_MSGH_BITS_COMPLEX;
544     messageBits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
545
546     header->msgh_bits = messageBits;
547     header->msgh_local_port = header->msgh_remote_port;
548     header->msgh_remote_port = exceptionPort;
549
550     // Now send along the message.
551     kern_return_t kr = mach_msg(header, MACH_SEND_MSG, header->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
552     if (kr != KERN_SUCCESS) {
553         LOG_ERROR("Failed to send message to real exception port. %s (%x)", mach_error_string(kr), kr);
554         ASSERT_NOT_REACHED();
555     }
556
557     connectionDidClose();
558 }
559
560 void Connection::setShouldCloseConnectionOnMachExceptions()
561 {
562     ASSERT(m_exceptionPort == MACH_PORT_NULL);
563
564     if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_exceptionPort) != KERN_SUCCESS)
565         ASSERT_NOT_REACHED();
566
567     if (mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)
568         ASSERT_NOT_REACHED();
569 }
570 #endif
571
572 IPC::Connection::Identifier Connection::identifier() const
573 {
574     return Identifier(m_isServer ? m_receivePort : m_sendPort, m_xpcConnection);
575 }
576
577 bool Connection::getAuditToken(audit_token_t& auditToken)
578 {
579     if (!m_xpcConnection)
580         return false;
581     
582     xpc_connection_get_audit_token(m_xpcConnection.get(), &auditToken);
583     return true;
584 }
585
586 bool Connection::kill()
587 {
588 #if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
589     if (m_xpcConnection) {
590         xpc_connection_kill(m_xpcConnection.get(), SIGKILL);
591         return true;
592     }
593 #endif
594
595     return false;
596 }
597     
598 void Connection::willSendSyncMessage(unsigned flags)
599 {
600 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
601     if ((flags & InformPlatformProcessWillSuspend) && WebCore::AXObjectCache::accessibilityEnabled())
602         _AXUIElementNotifyProcessSuspendStatus(AXSuspendStatusSuspended);
603 #endif
604 }
605
606 void Connection::didReceiveSyncReply(unsigned flags)
607 {
608 #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
609     if ((flags & InformPlatformProcessWillSuspend) && WebCore::AXObjectCache::accessibilityEnabled())
610         _AXUIElementNotifyProcessSuspendStatus(AXSuspendStatusRunning);
611 #endif
612 }    
613     
614 } // namespace IPC