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
46extern "C" void xpc_connection_get_audit_token(xpc_connection_t, audit_token_t*);
47extern "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
53typedef enum {
54    AXSuspendStatusRunning = 0,
55    AXSuspendStatusSuspended,
56} AXSuspendStatus;
57#endif
58
59#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
60extern "C" AXError _AXUIElementNotifyProcessSuspendStatus(AXSuspendStatus);
61#endif
62
63namespace IPC {
64
65static const size_t inlineMessageMaxSize = 4096;
66
67// Message flags.
68enum {
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.
76class ConnectionTerminationWatchdog {
77public:
78    static void createConnectionTerminationWatchdog(XPCPtr<xpc_connection_t>& xpcConnection, double intervalInSeconds)
79    {
80        new ConnectionTerminationWatchdog(xpcConnection, intervalInSeconds);
81    }
82
83private:
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::ProcessAndUIAssertion>(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#if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
97        xpc_connection_kill(m_xpcConnection.get(), SIGKILL);
98#endif
99        delete this;
100    }
101
102    XPCPtr<xpc_connection_t> m_xpcConnection;
103    RunLoop::Timer<ConnectionTerminationWatchdog> m_watchdogTimer;
104#if PLATFORM(IOS)
105    std::unique_ptr<WebKit::ProcessAndUIAssertion> m_assertion;
106#endif
107};
108
109void Connection::platformInvalidate()
110{
111    if (!m_isConnected)
112        return;
113
114    m_isConnected = false;
115
116    ASSERT(m_sendPort);
117    ASSERT(m_receivePort);
118
119    // Unregister our ports.
120    dispatch_source_cancel(m_deadNameSource);
121    dispatch_release(m_deadNameSource);
122    m_deadNameSource = 0;
123    m_sendPort = MACH_PORT_NULL;
124
125    dispatch_source_cancel(m_receivePortDataAvailableSource);
126    dispatch_release(m_receivePortDataAvailableSource);
127    m_receivePortDataAvailableSource = 0;
128    m_receivePort = MACH_PORT_NULL;
129
130#if !PLATFORM(IOS)
131    if (m_exceptionPort) {
132        dispatch_source_cancel(m_exceptionPortDataAvailableSource);
133        dispatch_release(m_exceptionPortDataAvailableSource);
134        m_exceptionPortDataAvailableSource = 0;
135        m_exceptionPort = MACH_PORT_NULL;
136    }
137#endif
138
139    m_xpcConnection = nullptr;
140}
141
142void Connection::terminateSoon(double intervalInSeconds)
143{
144    if (m_xpcConnection)
145        ConnectionTerminationWatchdog::createConnectionTerminationWatchdog(m_xpcConnection, intervalInSeconds);
146}
147
148void Connection::platformInitialize(Identifier identifier)
149{
150#if !PLATFORM(IOS)
151    m_exceptionPort = MACH_PORT_NULL;
152    m_exceptionPortDataAvailableSource = nullptr;
153#endif
154
155    if (m_isServer) {
156        m_receivePort = identifier.port;
157        m_sendPort = MACH_PORT_NULL;
158    } else {
159        m_receivePort = MACH_PORT_NULL;
160        m_sendPort = identifier.port;
161    }
162
163    m_deadNameSource = nullptr;
164    m_receivePortDataAvailableSource = nullptr;
165
166    m_xpcConnection = identifier.xpcConnection;
167}
168
169template<typename Function>
170static dispatch_source_t createDataAvailableSource(mach_port_t receivePort, WorkQueue& workQueue, Function&& function)
171{
172    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, receivePort, 0, workQueue.dispatchQueue());
173    dispatch_source_set_event_handler(source, function);
174
175    dispatch_source_set_cancel_handler(source, ^{
176        mach_port_mod_refs(mach_task_self(), receivePort, MACH_PORT_RIGHT_RECEIVE, -1);
177    });
178
179    return source;
180}
181
182bool Connection::open()
183{
184    if (m_isServer) {
185        ASSERT(m_receivePort);
186        ASSERT(!m_sendPort);
187
188    } else {
189        ASSERT(!m_receivePort);
190        ASSERT(m_sendPort);
191
192        // Create the receive port.
193        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_receivePort);
194
195#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
196        mach_port_set_attributes(mach_task_self(), m_receivePort, MACH_PORT_DENAP_RECEIVER, (mach_port_info_t)0, 0);
197#elif PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
198        mach_port_set_attributes(mach_task_self(), m_receivePort, MACH_PORT_IMPORTANCE_RECEIVER, (mach_port_info_t)0, 0);
199#endif
200
201        m_isConnected = true;
202
203        // Send the initialize message, which contains a send right for the server to use.
204        auto encoder = std::make_unique<MessageEncoder>("IPC", "InitializeConnection", 0);
205        encoder->encode(MachPort(m_receivePort, MACH_MSG_TYPE_MAKE_SEND));
206
207        sendMessage(WTF::move(encoder));
208
209        initializeDeadNameSource();
210    }
211
212    // Change the message queue length for the receive port.
213    setMachPortQueueLength(m_receivePort, MACH_PORT_QLIMIT_LARGE);
214
215    // Register the data available handler.
216    RefPtr<Connection> connection(this);
217    m_receivePortDataAvailableSource = createDataAvailableSource(m_receivePort, *m_connectionQueue, [connection] {
218        connection->receiveSourceEventHandler();
219    });
220
221#if !PLATFORM(IOS)
222    // If we have an exception port, register the data available handler and send over the port to the other end.
223    if (m_exceptionPort) {
224        m_exceptionPortDataAvailableSource = createDataAvailableSource(m_exceptionPort, *m_connectionQueue, [connection] {
225            connection->exceptionSourceEventHandler();
226        });
227
228        auto encoder = std::make_unique<MessageEncoder>("IPC", "SetExceptionPort", 0);
229        encoder->encode(MachPort(m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND));
230
231        sendMessage(WTF::move(encoder));
232    }
233#endif
234
235    ref();
236    dispatch_async(m_connectionQueue->dispatchQueue(), ^{
237        dispatch_resume(m_receivePortDataAvailableSource);
238
239        if (m_deadNameSource)
240            dispatch_resume(m_deadNameSource);
241#if !PLATFORM(IOS)
242        if (m_exceptionPortDataAvailableSource)
243            dispatch_resume(m_exceptionPortDataAvailableSource);
244#endif
245
246        deref();
247    });
248
249    return true;
250}
251
252static inline size_t machMessageSize(size_t bodySize, size_t numberOfPortDescriptors = 0, size_t numberOfOOLMemoryDescriptors = 0)
253{
254    size_t size = sizeof(mach_msg_header_t) + bodySize;
255    if (numberOfPortDescriptors || numberOfOOLMemoryDescriptors) {
256        size += sizeof(mach_msg_body_t);
257        if (numberOfPortDescriptors)
258            size += (numberOfPortDescriptors * sizeof(mach_msg_port_descriptor_t));
259        if (numberOfOOLMemoryDescriptors)
260            size += (numberOfOOLMemoryDescriptors * sizeof(mach_msg_ool_descriptor_t));
261    }
262    return round_msg(size);
263}
264
265bool Connection::platformCanSendOutgoingMessages() const
266{
267    return true;
268}
269
270bool Connection::sendOutgoingMessage(std::unique_ptr<MessageEncoder> encoder)
271{
272    Vector<Attachment> attachments = encoder->releaseAttachments();
273
274    size_t numberOfPortDescriptors = 0;
275    size_t numberOfOOLMemoryDescriptors = 0;
276    for (size_t i = 0; i < attachments.size(); ++i) {
277        Attachment::Type type = attachments[i].type();
278        if (type == Attachment::MachPortType)
279            numberOfPortDescriptors++;
280    }
281
282    size_t messageSize = machMessageSize(encoder->bufferSize(), numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
283
284    bool messageBodyIsOOL = false;
285    if (messageSize > inlineMessageMaxSize) {
286        messageBodyIsOOL = true;
287
288        numberOfOOLMemoryDescriptors++;
289        messageSize = machMessageSize(0, numberOfPortDescriptors, numberOfOOLMemoryDescriptors);
290    }
291
292    char stackBuffer[inlineMessageMaxSize];
293    char* buffer = &stackBuffer[0];
294    if (messageSize > inlineMessageMaxSize)
295        buffer = (char*)mmap(0, messageSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
296
297    bool isComplex = (numberOfPortDescriptors + numberOfOOLMemoryDescriptors > 0);
298
299    mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer);
300    header->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
301    header->msgh_size = messageSize;
302    header->msgh_remote_port = m_sendPort;
303    header->msgh_local_port = MACH_PORT_NULL;
304    header->msgh_id = 0;
305    if (messageBodyIsOOL)
306        header->msgh_id |= MessageBodyIsOutOfLine;
307
308    uint8_t* messageData;
309
310    if (isComplex) {
311        header->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
312
313        mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
314        body->msgh_descriptor_count = numberOfPortDescriptors + numberOfOOLMemoryDescriptors;
315        uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
316
317        for (size_t i = 0; i < attachments.size(); ++i) {
318            Attachment attachment = attachments[i];
319
320            mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
321            switch (attachment.type()) {
322            case Attachment::MachPortType:
323                descriptor->port.name = attachment.port();
324                descriptor->port.disposition = attachment.disposition();
325                descriptor->port.type = MACH_MSG_PORT_DESCRIPTOR;
326
327                descriptorData += sizeof(mach_msg_port_descriptor_t);
328                break;
329            default:
330                ASSERT_NOT_REACHED();
331            }
332        }
333
334        if (messageBodyIsOOL) {
335            mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
336
337            descriptor->out_of_line.address = encoder->buffer();
338            descriptor->out_of_line.size = encoder->bufferSize();
339            descriptor->out_of_line.copy = MACH_MSG_VIRTUAL_COPY;
340            descriptor->out_of_line.deallocate = false;
341            descriptor->out_of_line.type = MACH_MSG_OOL_DESCRIPTOR;
342
343            descriptorData += sizeof(mach_msg_ool_descriptor_t);
344        }
345
346        messageData = descriptorData;
347    } else
348        messageData = (uint8_t*)(header + 1);
349
350    // Copy the data if it is not being sent out-of-line.
351    if (!messageBodyIsOOL)
352        memcpy(messageData, encoder->buffer(), encoder->bufferSize());
353
354    ASSERT(m_sendPort);
355
356    // Send the message.
357    kern_return_t kr = mach_msg(header, MACH_SEND_MSG, messageSize, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
358    if (kr != KERN_SUCCESS) {
359        // FIXME: What should we do here?
360    }
361
362    if (buffer != &stackBuffer[0])
363        munmap(buffer, messageSize);
364
365    return true;
366}
367
368void Connection::initializeDeadNameSource()
369{
370    m_deadNameSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, m_sendPort, 0, m_connectionQueue->dispatchQueue());
371    dispatch_source_set_event_handler(m_deadNameSource, bind(&Connection::connectionDidClose, this));
372
373    mach_port_t sendPort = m_sendPort;
374    dispatch_source_set_cancel_handler(m_deadNameSource, ^{
375        // Release our send right.
376        mach_port_deallocate(mach_task_self(), sendPort);
377    });
378}
379
380static std::unique_ptr<MessageDecoder> createMessageDecoder(mach_msg_header_t* header)
381{
382    if (!(header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
383        // We have a simple message.
384        uint8_t* body = reinterpret_cast<uint8_t*>(header + 1);
385        size_t bodySize = header->msgh_size - sizeof(mach_msg_header_t);
386
387        return std::make_unique<MessageDecoder>(DataReference(body, bodySize), Vector<Attachment>());
388    }
389
390    bool messageBodyIsOOL = header->msgh_id & MessageBodyIsOutOfLine;
391
392    mach_msg_body_t* body = reinterpret_cast<mach_msg_body_t*>(header + 1);
393    mach_msg_size_t numDescriptors = body->msgh_descriptor_count;
394    ASSERT(numDescriptors);
395
396    uint8_t* descriptorData = reinterpret_cast<uint8_t*>(body + 1);
397
398    // If the message body was sent out-of-line, don't treat the last descriptor
399    // as an attachment, since it is really the message body.
400    if (messageBodyIsOOL)
401        --numDescriptors;
402
403    // Build attachment list
404    Vector<Attachment> attachments(numDescriptors);
405
406    for (mach_msg_size_t i = 0; i < numDescriptors; ++i) {
407        mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
408
409        switch (descriptor->type.type) {
410        case MACH_MSG_PORT_DESCRIPTOR:
411            attachments[numDescriptors - i - 1] = Attachment(descriptor->port.name, descriptor->port.disposition);
412            descriptorData += sizeof(mach_msg_port_descriptor_t);
413            break;
414        default:
415            ASSERT(false && "Unhandled descriptor type");
416        }
417    }
418
419    if (messageBodyIsOOL) {
420        mach_msg_descriptor_t* descriptor = reinterpret_cast<mach_msg_descriptor_t*>(descriptorData);
421        ASSERT(descriptor->type.type == MACH_MSG_OOL_DESCRIPTOR);
422
423        uint8_t* messageBody = static_cast<uint8_t*>(descriptor->out_of_line.address);
424        size_t messageBodySize = descriptor->out_of_line.size;
425
426        auto decoder = std::make_unique<MessageDecoder>(DataReference(messageBody, messageBodySize), WTF::move(attachments));
427
428        vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(descriptor->out_of_line.address), descriptor->out_of_line.size);
429
430        return decoder;
431    }
432
433    uint8_t* messageBody = descriptorData;
434    size_t messageBodySize = header->msgh_size - (descriptorData - reinterpret_cast<uint8_t*>(header));
435
436    return std::make_unique<MessageDecoder>(DataReference(messageBody, messageBodySize), attachments);
437}
438
439// The receive buffer size should always include the maximum trailer size.
440static const size_t receiveBufferSize = inlineMessageMaxSize + MAX_TRAILER_SIZE;
441typedef Vector<char, receiveBufferSize> ReceiveBuffer;
442
443static mach_msg_header_t* readFromMachPort(mach_port_t machPort, ReceiveBuffer& buffer)
444{
445    buffer.resize(receiveBufferSize);
446
447    mach_msg_header_t* header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
448    kern_return_t kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
449    if (kr == MACH_RCV_TIMED_OUT)
450        return 0;
451
452    if (kr == MACH_RCV_TOO_LARGE) {
453        // The message was too large, resize the buffer and try again.
454        buffer.resize(header->msgh_size + MAX_TRAILER_SIZE);
455        header = reinterpret_cast<mach_msg_header_t*>(buffer.data());
456
457        kr = mach_msg(header, MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0, buffer.size(), machPort, 0, MACH_PORT_NULL);
458        ASSERT(kr != MACH_RCV_TOO_LARGE);
459    }
460
461    if (kr != MACH_MSG_SUCCESS) {
462        ASSERT_NOT_REACHED();
463        return 0;
464    }
465
466    return header;
467}
468
469void Connection::receiveSourceEventHandler()
470{
471    ReceiveBuffer buffer;
472
473    mach_msg_header_t* header = readFromMachPort(m_receivePort, buffer);
474    if (!header)
475        return;
476
477    std::unique_ptr<MessageDecoder> decoder = createMessageDecoder(header);
478    ASSERT(decoder);
479
480#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
481    decoder->setImportanceAssertion(std::make_unique<ImportanceAssertion>(header));
482#endif
483
484    if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "InitializeConnection") {
485        ASSERT(m_isServer);
486        ASSERT(!m_isConnected);
487        ASSERT(!m_sendPort);
488
489        MachPort port;
490        if (!decoder->decode(port)) {
491            // FIXME: Disconnect.
492            return;
493        }
494
495        m_sendPort = port.port();
496
497        if (m_sendPort) {
498            initializeDeadNameSource();
499            dispatch_resume(m_deadNameSource);
500        }
501
502        m_isConnected = true;
503
504        // Send any pending outgoing messages.
505        sendOutgoingMessages();
506
507        return;
508    }
509
510#if !PLATFORM(IOS)
511    if (decoder->messageReceiverName() == "IPC" && decoder->messageName() == "SetExceptionPort") {
512        if (m_isServer) {
513            // Server connections aren't supposed to have their exception ports overriden. Treat this as an invalid message.
514            m_clientRunLoop.dispatch(bind(&Connection::dispatchDidReceiveInvalidMessage, this, decoder->messageReceiverName().toString(), decoder->messageName().toString()));
515            return;
516        }
517        MachPort exceptionPort;
518        if (!decoder->decode(exceptionPort))
519            return;
520
521        setMachExceptionPort(exceptionPort.port());
522        return;
523    }
524#endif
525
526    processIncomingMessage(WTF::move(decoder));
527}
528
529#if !PLATFORM(IOS)
530void Connection::exceptionSourceEventHandler()
531{
532    ReceiveBuffer buffer;
533
534    mach_msg_header_t* header = readFromMachPort(m_exceptionPort, buffer);
535    if (!header)
536        return;
537
538    // We've read the exception message. Now send it on to the real exception port.
539
540    // The remote port should have a send once right.
541    ASSERT(MACH_MSGH_BITS_REMOTE(header->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE);
542
543    // Now get the real exception port.
544    mach_port_t exceptionPort = machExceptionPort();
545
546    // First, get the complex bit from the source message.
547    mach_msg_bits_t messageBits = header->msgh_bits & MACH_MSGH_BITS_COMPLEX;
548    messageBits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
549
550    header->msgh_bits = messageBits;
551    header->msgh_local_port = header->msgh_remote_port;
552    header->msgh_remote_port = exceptionPort;
553
554    // Now send along the message.
555    kern_return_t kr = mach_msg(header, MACH_SEND_MSG, header->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
556    if (kr != KERN_SUCCESS) {
557        LOG_ERROR("Failed to send message to real exception port. %s (%x)", mach_error_string(kr), kr);
558        ASSERT_NOT_REACHED();
559    }
560
561    connectionDidClose();
562}
563
564void Connection::setShouldCloseConnectionOnMachExceptions()
565{
566    ASSERT(m_exceptionPort == MACH_PORT_NULL);
567
568    if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_exceptionPort) != KERN_SUCCESS)
569        ASSERT_NOT_REACHED();
570
571    if (mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)
572        ASSERT_NOT_REACHED();
573}
574#endif
575
576IPC::Connection::Identifier Connection::identifier() const
577{
578    return Identifier(m_isServer ? m_receivePort : m_sendPort, m_xpcConnection);
579}
580
581bool Connection::getAuditToken(audit_token_t& auditToken)
582{
583    if (!m_xpcConnection)
584        return false;
585
586    xpc_connection_get_audit_token(m_xpcConnection.get(), &auditToken);
587    return true;
588}
589
590bool Connection::kill()
591{
592#if PLATFORM(IOS) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
593    if (m_xpcConnection) {
594        xpc_connection_kill(m_xpcConnection.get(), SIGKILL);
595        return true;
596    }
597#endif
598
599    return false;
600}
601
602void Connection::willSendSyncMessage(unsigned flags)
603{
604#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
605    if ((flags & InformPlatformProcessWillSuspend) && WebCore::AXObjectCache::accessibilityEnabled())
606        _AXUIElementNotifyProcessSuspendStatus(AXSuspendStatusSuspended);
607#endif
608}
609
610void Connection::didReceiveSyncReply(unsigned flags)
611{
612#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
613    if ((flags & InformPlatformProcessWillSuspend) && WebCore::AXObjectCache::accessibilityEnabled())
614        _AXUIElementNotifyProcessSuspendStatus(AXSuspendStatusRunning);
615#endif
616}
617
618} // namespace IPC
619