diff options
author | Andras Becsi <andras.becsi@digia.com> | 2014-03-18 13:16:26 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-03-20 15:55:39 +0100 |
commit | 3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch) | |
tree | 92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/ipc | |
parent | e90d7c4b152c56919d963987e2503f9909a666d2 (diff) | |
download | qtwebengine-chromium-3f0f86b0caed75241fa71c95a5d73bc0164348c5.tar.gz |
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies
needed on Windows.
Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42
Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu>
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/ipc')
26 files changed, 487 insertions, 168 deletions
diff --git a/chromium/ipc/OWNERS b/chromium/ipc/OWNERS index eaf88320e66..37a61fa0463 100644 --- a/chromium/ipc/OWNERS +++ b/chromium/ipc/OWNERS @@ -13,8 +13,10 @@ dmichael@chromium.org per-file ipc_message_start.h=set noparent per-file ipc_message_start.h=cdn@chromium.org per-file ipc_message_start.h=cevans@chromium.org +per-file ipc_message_start.h=dcheng@chromium.org per-file ipc_message_start.h=jln@chromium.org per-file ipc_message_start.h=jschuh@chromium.org per-file ipc_message_start.h=palmer@chromium.org per-file ipc_message_start.h=tsepez@chromium.org per-file ipc_message_start.h=kenrb@chromium.org +per-file ipc_message_start.h=nasko@chromium.org diff --git a/chromium/ipc/file_descriptor_set_posix.cc b/chromium/ipc/file_descriptor_set_posix.cc index 584efec14ae..1aa86a7f008 100644 --- a/chromium/ipc/file_descriptor_set_posix.cc +++ b/chromium/ipc/file_descriptor_set_posix.cc @@ -31,7 +31,7 @@ FileDescriptorSet::~FileDescriptorSet() { for (unsigned i = consumed_descriptor_highwater_; i < descriptors_.size(); ++i) { if (descriptors_[i].auto_close) - if (HANDLE_EINTR(close(descriptors_[i].fd)) < 0) + if (IGNORE_EINTR(close(descriptors_[i].fd)) < 0) PLOG(ERROR) << "close"; } } @@ -119,13 +119,23 @@ void FileDescriptorSet::CommitAll() { for (std::vector<base::FileDescriptor>::iterator i = descriptors_.begin(); i != descriptors_.end(); ++i) { if (i->auto_close) - if (HANDLE_EINTR(close(i->fd)) < 0) + if (IGNORE_EINTR(close(i->fd)) < 0) PLOG(ERROR) << "close"; } descriptors_.clear(); consumed_descriptor_highwater_ = 0; } +void FileDescriptorSet::ReleaseFDsToClose(std::vector<int>* fds) { + for (std::vector<base::FileDescriptor>::iterator + i = descriptors_.begin(); i != descriptors_.end(); ++i) { + if (i->auto_close) + fds->push_back(i->fd); + } + descriptors_.clear(); + consumed_descriptor_highwater_ = 0; +} + void FileDescriptorSet::SetDescriptors(const int* buffer, unsigned count) { DCHECK(count <= kMaxDescriptorsPerMessage); DCHECK_EQ(descriptors_.size(), 0u); diff --git a/chromium/ipc/file_descriptor_set_posix.h b/chromium/ipc/file_descriptor_set_posix.h index f9c6033c2a6..b413b4a2212 100644 --- a/chromium/ipc/file_descriptor_set_posix.h +++ b/chromium/ipc/file_descriptor_set_posix.h @@ -77,6 +77,9 @@ class IPC_EXPORT FileDescriptorSet // Returns true if any contained file descriptors appear to be handles to a // directory. bool ContainsDirectoryDescriptor() const; + // Fetch all filedescriptors with the "auto close" property. + // Used instead of CommitAll() when closing must be handled manually. + void ReleaseFDsToClose(std::vector<int>* fds); // --------------------------------------------------------------------------- diff --git a/chromium/ipc/file_descriptor_set_posix_unittest.cc b/chromium/ipc/file_descriptor_set_posix_unittest.cc index b4a01414a55..d9107f9f881 100644 --- a/chromium/ipc/file_descriptor_set_posix_unittest.cc +++ b/chromium/ipc/file_descriptor_set_posix_unittest.cc @@ -24,8 +24,8 @@ int GetSafeFd() { bool VerifyClosed(int fd) { const int duped = dup(fd); if (duped != -1) { - EXPECT_NE(HANDLE_EINTR(close(duped)), -1); - EXPECT_NE(HANDLE_EINTR(close(fd)), -1); + EXPECT_NE(IGNORE_EINTR(close(duped)), -1); + EXPECT_NE(IGNORE_EINTR(close(fd)), -1); return false; } return true; diff --git a/chromium/ipc/ipc.gyp b/chromium/ipc/ipc.gyp index a2476511a84..ace836b3a1b 100644 --- a/chromium/ipc/ipc.gyp +++ b/chromium/ipc/ipc.gyp @@ -37,7 +37,6 @@ 'test_support_ipc', '../base/base.gyp:base', '../base/base.gyp:base_i18n', - '../base/base.gyp:run_all_unittests', '../base/base.gyp:test_support_base', '../testing/gtest.gyp:gtest', ], @@ -57,6 +56,7 @@ 'ipc_sync_message_unittest.h', 'ipc_test_base.cc', 'ipc_test_base.h', + 'run_all_unittests.cc', 'sync_socket_unittest.cc', 'unix_domain_socket_util_unittest.cc', ], diff --git a/chromium/ipc/ipc_channel.h b/chromium/ipc/ipc_channel.h index f65a62b9cc9..7e09a806f7a 100644 --- a/chromium/ipc/ipc_channel.h +++ b/chromium/ipc/ipc_channel.h @@ -75,15 +75,22 @@ class IPC_EXPORT Channel : public Sender { #endif }; - // The Hello message is internal to the Channel class. It is sent - // by the peer when the channel is connected. The message contains - // just the process id (pid). The message has a special routing_id - // (MSG_ROUTING_NONE) and type (HELLO_MESSAGE_TYPE). + // Messages internal to the IPC implementation are defined here. + // Uses Maximum value of message type (uint16), to avoid conflicting + // with normal message types, which are enumeration constants starting from 0. enum { - HELLO_MESSAGE_TYPE = kuint16max // Maximum value of message type (uint16), - // to avoid conflicting with normal - // message types, which are enumeration - // constants starting from 0. + // The Hello message is sent by the peer when the channel is connected. + // The message contains just the process id (pid). + // The message has a special routing_id (MSG_ROUTING_NONE) + // and type (HELLO_MESSAGE_TYPE). + HELLO_MESSAGE_TYPE = kuint16max, + // The CLOSE_FD_MESSAGE_TYPE is used in the IPC class to + // work around a bug in sendmsg() on Mac. When an FD is sent + // over the socket, a CLOSE_FD_MESSAGE is sent with hops = 2. + // The client will return the message with hops = 1, *after* it + // has received the message that contains the FD. When we + // receive it again on the sender side, we close the FD. + CLOSE_FD_MESSAGE_TYPE = HELLO_MESSAGE_TYPE - 1 }; // The maximum message size in bytes. Attempting to receive a message of this diff --git a/chromium/ipc/ipc_channel_factory.cc b/chromium/ipc/ipc_channel_factory.cc index f3ad11a6b4f..5c24284f95d 100644 --- a/chromium/ipc/ipc_channel_factory.cc +++ b/chromium/ipc/ipc_channel_factory.cc @@ -76,7 +76,7 @@ void ChannelFactory::OnFileCanWriteWithoutBlocking(int fd) { void ChannelFactory::Close() { if (listen_fd_ < 0) return; - if (HANDLE_EINTR(close(listen_fd_)) < 0) + if (IGNORE_EINTR(close(listen_fd_)) < 0) PLOG(ERROR) << "close"; listen_fd_ = -1; if (unlink(path_.value().c_str()) < 0) diff --git a/chromium/ipc/ipc_channel_nacl.cc b/chromium/ipc/ipc_channel_nacl.cc index 860815e91cb..1ecd5718245 100644 --- a/chromium/ipc/ipc_channel_nacl.cc +++ b/chromium/ipc/ipc_channel_nacl.cc @@ -344,7 +344,7 @@ bool Channel::ChannelImpl::DidEmptyInputBuffers() { return input_fds_.empty(); } -void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { +void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) { // The trusted side IPC::Channel should handle the "hello" handshake; we // should not receive the "Hello" message. NOTREACHED(); diff --git a/chromium/ipc/ipc_channel_nacl.h b/chromium/ipc/ipc_channel_nacl.h index 7c8960f6d71..a21730eb813 100644 --- a/chromium/ipc/ipc_channel_nacl.h +++ b/chromium/ipc/ipc_channel_nacl.h @@ -60,7 +60,7 @@ class Channel::ChannelImpl : public internal::ChannelReader { int* bytes_read) OVERRIDE; virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE; virtual bool DidEmptyInputBuffers() OVERRIDE; - virtual void HandleHelloMessage(const Message& msg) OVERRIDE; + virtual void HandleInternalMessage(const Message& msg) OVERRIDE; Mode mode_; bool waiting_connect_; diff --git a/chromium/ipc/ipc_channel_posix.cc b/chromium/ipc/ipc_channel_posix.cc index 98a7cd8a9fa..87885329001 100644 --- a/chromium/ipc/ipc_channel_posix.cc +++ b/chromium/ipc/ipc_channel_posix.cc @@ -206,9 +206,9 @@ bool SocketPair(int* fd1, int* fd2) { if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) { PLOG(ERROR) << "fcntl(O_NONBLOCK)"; - if (HANDLE_EINTR(close(pipe_fds[0])) < 0) + if (IGNORE_EINTR(close(pipe_fds[0])) < 0) PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipe_fds[1])) < 0) + if (IGNORE_EINTR(close(pipe_fds[1])) < 0) PLOG(ERROR) << "close"; return false; } @@ -347,6 +347,27 @@ bool Channel::ChannelImpl::Connect() { return did_connect; } +void Channel::ChannelImpl::CloseFileDescriptors(Message* msg) { +#if defined(OS_MACOSX) + // There is a bug on OSX which makes it dangerous to close + // a file descriptor while it is in transit. So instead we + // store the file descriptor in a set and send a message to + // the recipient, which is queued AFTER the message that + // sent the FD. The recipient will reply to the message, + // letting us know that it is now safe to close the file + // descriptor. For more information, see: + // http://crbug.com/298276 + std::vector<int> to_close; + msg->file_descriptor_set()->ReleaseFDsToClose(&to_close); + for (size_t i = 0; i < to_close.size(); i++) { + fds_to_close_.insert(to_close[i]); + QueueCloseFDMessage(to_close[i], 2); + } +#else + msg->file_descriptor_set()->CommitAll(); +#endif +} + bool Channel::ChannelImpl::ProcessOutgoingMessages() { DCHECK(!waiting_connect_); // Why are we trying to send messages if there's // no connection? @@ -419,7 +440,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() { msgh.msg_iov = &iov; msgh.msg_controllen = 0; if (bytes_written > 0) { - msg->file_descriptor_set()->CommitAll(); + CloseFileDescriptors(msg); } } #endif // IPC_USES_READWRITE @@ -440,7 +461,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() { } } if (bytes_written > 0) - msg->file_descriptor_set()->CommitAll(); + CloseFileDescriptors(msg); if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) { #if defined(OS_MACOSX) @@ -526,7 +547,7 @@ void Channel::ChannelImpl::CloseClientFileDescriptor() { base::AutoLock lock(client_pipe_lock_); if (client_pipe_ != -1) { PipeMap::GetInstance()->Remove(pipe_name_); - if (HANDLE_EINTR(close(client_pipe_)) < 0) + if (IGNORE_EINTR(close(client_pipe_)) < 0) PLOG(ERROR) << "close " << pipe_name_; client_pipe_ = -1; } @@ -550,18 +571,18 @@ void Channel::ChannelImpl::ResetToAcceptingConnectionState() { read_watcher_.StopWatchingFileDescriptor(); write_watcher_.StopWatchingFileDescriptor(); if (pipe_ != -1) { - if (HANDLE_EINTR(close(pipe_)) < 0) + if (IGNORE_EINTR(close(pipe_)) < 0) PLOG(ERROR) << "close pipe_ " << pipe_name_; pipe_ = -1; } #if defined(IPC_USES_READWRITE) if (fd_pipe_ != -1) { - if (HANDLE_EINTR(close(fd_pipe_)) < 0) + if (IGNORE_EINTR(close(fd_pipe_)) < 0) PLOG(ERROR) << "close fd_pipe_ " << pipe_name_; fd_pipe_ = -1; } if (remote_fd_pipe_ != -1) { - if (HANDLE_EINTR(close(remote_fd_pipe_)) < 0) + if (IGNORE_EINTR(close(remote_fd_pipe_)) < 0) PLOG(ERROR) << "close remote_fd_pipe_ " << pipe_name_; remote_fd_pipe_ = -1; } @@ -575,6 +596,17 @@ void Channel::ChannelImpl::ResetToAcceptingConnectionState() { // Close any outstanding, received file descriptors. ClearInputFDs(); + +#if defined(OS_MACOSX) + // Clear any outstanding, sent file descriptors. + for (std::set<int>::iterator i = fds_to_close_.begin(); + i != fds_to_close_.end(); + ++i) { + if (IGNORE_EINTR(close(*i)) < 0) + PLOG(ERROR) << "close"; + } + fds_to_close_.clear(); +#endif } // static @@ -592,7 +624,6 @@ void Channel::ChannelImpl::SetGlobalPid(int pid) { // Called by libevent when we can read from the pipe without blocking. void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { - bool send_server_hello_msg = false; if (fd == server_listen_pipe_) { int new_pipe = 0; if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe) || @@ -606,7 +637,7 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { // close our new descriptor. if (HANDLE_EINTR(shutdown(new_pipe, SHUT_RDWR)) < 0) DPLOG(ERROR) << "shutdown " << pipe_name_; - if (HANDLE_EINTR(close(new_pipe)) < 0) + if (IGNORE_EINTR(close(new_pipe)) < 0) DPLOG(ERROR) << "close " << pipe_name_; listener()->OnChannelDenied(); return; @@ -631,18 +662,16 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { if (!AcceptConnection()) { NOTREACHED() << "AcceptConnection should not fail on server"; } - send_server_hello_msg = true; waiting_connect_ = false; } else if (fd == pipe_) { if (waiting_connect_ && (mode_ & MODE_SERVER_FLAG)) { - send_server_hello_msg = true; waiting_connect_ = false; } if (!ProcessIncomingMessages()) { // ClosePipeOnError may delete this object, so we mustn't call // ProcessOutgoingMessages. - send_server_hello_msg = false; ClosePipeOnError(); + return; } } else { NOTREACHED() << "Unknown pipe " << fd; @@ -651,9 +680,11 @@ void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) { // If we're a server and handshaking, then we want to make sure that we // only send our handshake message after we've processed the client's. // This gives us a chance to kill the client if the incoming handshake - // is invalid. - if (send_server_hello_msg) { - ProcessOutgoingMessages(); + // is invalid. This also flushes any closefd messagse. + if (!is_blocked_on_write_) { + if (!ProcessOutgoingMessages()) { + ClosePipeOnError(); + } } } @@ -896,35 +927,86 @@ bool Channel::ChannelImpl::ExtractFileDescriptorsFromMsghdr(msghdr* msg) { void Channel::ChannelImpl::ClearInputFDs() { for (size_t i = 0; i < input_fds_.size(); ++i) { - if (HANDLE_EINTR(close(input_fds_[i])) < 0) + if (IGNORE_EINTR(close(input_fds_[i])) < 0) PLOG(ERROR) << "close "; } input_fds_.clear(); } -void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { +void Channel::ChannelImpl::QueueCloseFDMessage(int fd, int hops) { + switch (hops) { + case 1: + case 2: { + // Create the message + scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE, + CLOSE_FD_MESSAGE_TYPE, + IPC::Message::PRIORITY_NORMAL)); + if (!msg->WriteInt(hops - 1) || !msg->WriteInt(fd)) { + NOTREACHED() << "Unable to pickle close fd."; + } + // Send(msg.release()); + output_queue_.push(msg.release()); + break; + } + + default: + NOTREACHED(); + break; + } +} + +void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) { // The Hello message contains only the process id. PickleIterator iter(msg); - int pid; - if (!msg.ReadInt(&iter, &pid)) - NOTREACHED(); -#if defined(IPC_USES_READWRITE) - if (mode_ & MODE_SERVER_FLAG) { - // With IPC_USES_READWRITE, the Hello message from the client to the - // server also contains the fd_pipe_, which will be used for all - // subsequent file descriptor passing. - DCHECK_EQ(msg.file_descriptor_set()->size(), 1U); - base::FileDescriptor descriptor; - if (!msg.ReadFileDescriptor(&iter, &descriptor)) { + switch (msg.type()) { + default: NOTREACHED(); - } - fd_pipe_ = descriptor.fd; - CHECK(descriptor.auto_close); - } + break; + + case Channel::HELLO_MESSAGE_TYPE: + int pid; + if (!msg.ReadInt(&iter, &pid)) + NOTREACHED(); + +#if defined(IPC_USES_READWRITE) + if (mode_ & MODE_SERVER_FLAG) { + // With IPC_USES_READWRITE, the Hello message from the client to the + // server also contains the fd_pipe_, which will be used for all + // subsequent file descriptor passing. + DCHECK_EQ(msg.file_descriptor_set()->size(), 1U); + base::FileDescriptor descriptor; + if (!msg.ReadFileDescriptor(&iter, &descriptor)) { + NOTREACHED(); + } + fd_pipe_ = descriptor.fd; + CHECK(descriptor.auto_close); + } #endif // IPC_USES_READWRITE - peer_pid_ = pid; - listener()->OnChannelConnected(pid); + peer_pid_ = pid; + listener()->OnChannelConnected(pid); + break; + +#if defined(OS_MACOSX) + case Channel::CLOSE_FD_MESSAGE_TYPE: + int fd, hops; + if (!msg.ReadInt(&iter, &hops)) + NOTREACHED(); + if (!msg.ReadInt(&iter, &fd)) + NOTREACHED(); + if (hops == 0) { + if (fds_to_close_.erase(fd) > 0) { + if (IGNORE_EINTR(close(fd)) < 0) + PLOG(ERROR) << "close"; + } else { + NOTREACHED(); + } + } else { + QueueCloseFDMessage(fd, hops); + } + break; +#endif + } } void Channel::ChannelImpl::Close() { @@ -938,7 +1020,7 @@ void Channel::ChannelImpl::Close() { must_unlink_ = false; } if (server_listen_pipe_ != -1) { - if (HANDLE_EINTR(close(server_listen_pipe_)) < 0) + if (IGNORE_EINTR(close(server_listen_pipe_)) < 0) DPLOG(ERROR) << "close " << server_listen_pipe_; server_listen_pipe_ = -1; // Unregister libevent for the listening socket and close it. diff --git a/chromium/ipc/ipc_channel_posix.h b/chromium/ipc/ipc_channel_posix.h index 645a1303713..1e587c13eb0 100644 --- a/chromium/ipc/ipc_channel_posix.h +++ b/chromium/ipc/ipc_channel_posix.h @@ -10,6 +10,7 @@ #include <sys/socket.h> // for CMSG macros #include <queue> +#include <set> #include <string> #include <vector> @@ -80,6 +81,8 @@ class Channel::ChannelImpl : public internal::ChannelReader, void ClosePipeOnError(); int GetHelloMessageProcId(); void QueueHelloMessage(); + void CloseFileDescriptors(Message* msg); + void QueueCloseFDMessage(int fd, int hops); // ChannelReader implementation. virtual ReadState ReadData(char* buffer, @@ -87,7 +90,7 @@ class Channel::ChannelImpl : public internal::ChannelReader, int* bytes_read) OVERRIDE; virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE; virtual bool DidEmptyInputBuffers() OVERRIDE; - virtual void HandleHelloMessage(const Message& msg) OVERRIDE; + virtual void HandleInternalMessage(const Message& msg) OVERRIDE; #if defined(IPC_USES_READWRITE) // Reads the next message from the fd_pipe_ and appends them to the @@ -184,6 +187,13 @@ class Channel::ChannelImpl : public internal::ChannelReader, // implementation! std::vector<int> input_fds_; +#if defined(OS_MACOSX) + // On OSX, sent FDs must not be closed until we get an ack. + // Keep track of sent FDs here to make sure the remote is not + // trying to bamboozle us. + std::set<int> fds_to_close_; +#endif + // True if we are responsible for unlinking the unix domain socket file. bool must_unlink_; diff --git a/chromium/ipc/ipc_channel_posix_unittest.cc b/chromium/ipc/ipc_channel_posix_unittest.cc index 66ddeb2b496..dbd854e16c6 100644 --- a/chromium/ipc/ipc_channel_posix_unittest.cc +++ b/chromium/ipc/ipc_channel_posix_unittest.cc @@ -159,7 +159,7 @@ void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle, // Make sure the path we need exists. base::FilePath path(name); base::FilePath dir_path = path.DirName(); - ASSERT_TRUE(file_util::CreateDirectory(dir_path)); + ASSERT_TRUE(base::CreateDirectory(dir_path)); ASSERT_GE(bind(socket_fd, reinterpret_cast<struct sockaddr *>(&server_address), server_address_len), 0) << server_address.sun_path @@ -219,7 +219,7 @@ TEST_F(IPCChannelPosixTest, BasicConnected) { ASSERT_TRUE(channel.Connect()); ASSERT_FALSE(channel.AcceptsConnections()); channel.Close(); - ASSERT_TRUE(HANDLE_EINTR(close(pipe_fds[1])) == 0); + ASSERT_TRUE(IGNORE_EINTR(close(pipe_fds[1])) == 0); // Make sure that we can use the socket that is created for us by // a standard channel. diff --git a/chromium/ipc/ipc_channel_proxy.cc b/chromium/ipc/ipc_channel_proxy.cc index 45512f97e18..18ed3041336 100644 --- a/chromium/ipc/ipc_channel_proxy.cc +++ b/chromium/ipc/ipc_channel_proxy.cc @@ -36,10 +36,6 @@ bool ChannelProxy::MessageFilter::OnMessageReceived(const Message& message) { return false; } -void ChannelProxy::MessageFilter::OnDestruct() const { - delete this; -} - ChannelProxy::MessageFilter::~MessageFilter() {} //------------------------------------------------------------------------------ @@ -292,14 +288,12 @@ ChannelProxy::ChannelProxy(const IPC::ChannelHandle& channel_handle, Listener* listener, base::SingleThreadTaskRunner* ipc_task_runner) : context_(new Context(listener, ipc_task_runner)), - outgoing_message_filter_(NULL), did_init_(false) { Init(channel_handle, mode, true); } ChannelProxy::ChannelProxy(Context* context) : context_(context), - outgoing_message_filter_(NULL), did_init_(false) { } @@ -362,8 +356,6 @@ bool ChannelProxy::Send(Message* message) { // TODO(alexeypa): add DCHECK(CalledOnValidThread()) here. Currently there are // tests that call Send() from a wrong thread. See http://crbug.com/163523. - if (outgoing_message_filter()) - message = outgoing_message_filter()->Rewrite(message); #ifdef IPC_MESSAGE_LOG_ENABLED Logging::GetInstance()->OnSendMessage(message, context_->channel_id()); diff --git a/chromium/ipc/ipc_channel_proxy.h b/chromium/ipc/ipc_channel_proxy.h index 4d5a7d45ec2..1f5ecf450df 100644 --- a/chromium/ipc/ipc_channel_proxy.h +++ b/chromium/ipc/ipc_channel_proxy.h @@ -54,12 +54,11 @@ class SendCallbackHelper; // class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe { public: - struct MessageFilterTraits; // A class that receives messages on the thread where the IPC channel is // running. It can choose to prevent the default action for an IPC message. class IPC_EXPORT MessageFilter - : public base::RefCountedThreadSafe<MessageFilter, MessageFilterTraits> { + : public base::RefCountedThreadSafe<MessageFilter> { public: MessageFilter(); @@ -89,33 +88,11 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe { // the message be handled in the default way. virtual bool OnMessageReceived(const Message& message); - // Called when the message filter is about to be deleted. This gives - // derived classes the option of controlling which thread they're deleted - // on etc. - virtual void OnDestruct() const; - protected: virtual ~MessageFilter(); private: - friend class base::RefCountedThreadSafe<MessageFilter, - MessageFilterTraits>; - }; - - struct MessageFilterTraits { - static void Destruct(const MessageFilter* filter) { - filter->OnDestruct(); - } - }; - - - // Interface for a filter to be imposed on outgoing messages which can - // re-write the message. Used mainly for testing. - class OutgoingMessageFilter { - public: - // Returns a re-written message, freeing the original, or simply the - // original unchanged if no rewrite indicated. - virtual Message *Rewrite(Message *message) = 0; + friend class base::RefCountedThreadSafe<MessageFilter>; }; // Initializes a channel proxy. The channel_handle and mode parameters are @@ -166,10 +143,6 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe { void AddFilter(MessageFilter* filter); void RemoveFilter(MessageFilter* filter); - void set_outgoing_message_filter(OutgoingMessageFilter* filter) { - outgoing_message_filter_ = filter; - } - // Called to clear the pointer to the IPC task runner when it's going away. void ClearIPCTaskRunner(); @@ -270,10 +243,6 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe { Context* context() { return context_.get(); } - OutgoingMessageFilter* outgoing_message_filter() { - return outgoing_message_filter_; - } - private: friend class SendCallbackHelper; @@ -282,8 +251,6 @@ class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe { // that involves this data. scoped_refptr<Context> context_; - OutgoingMessageFilter* outgoing_message_filter_; - // Whether the channel has been initialized. bool did_init_; }; diff --git a/chromium/ipc/ipc_channel_reader.cc b/chromium/ipc/ipc_channel_reader.cc index 9055deb1775..2ee7449ea8d 100644 --- a/chromium/ipc/ipc_channel_reader.cc +++ b/chromium/ipc/ipc_channel_reader.cc @@ -38,9 +38,15 @@ bool ChannelReader::AsyncReadComplete(int bytes_read) { return DispatchInputData(input_buf_, bytes_read); } +bool ChannelReader::IsInternalMessage(const Message& m) const { + return m.routing_id() == MSG_ROUTING_NONE && + m.type() >= Channel::CLOSE_FD_MESSAGE_TYPE && + m.type() <= Channel::HELLO_MESSAGE_TYPE; +} + bool ChannelReader::IsHelloMessage(const Message& m) const { return m.routing_id() == MSG_ROUTING_NONE && - m.type() == Channel::HELLO_MESSAGE_TYPE; + m.type() == Channel::HELLO_MESSAGE_TYPE; } bool ChannelReader::DispatchInputData(const char* input_data, @@ -84,8 +90,8 @@ bool ChannelReader::DispatchInputData(const char* input_data, "line", IPC_MESSAGE_ID_LINE(m.type())); #endif m.TraceMessageEnd(); - if (IsHelloMessage(m)) - HandleHelloMessage(m); + if (IsInternalMessage(m)) + HandleInternalMessage(m); else listener_->OnMessageReceived(m); p = message_tail; diff --git a/chromium/ipc/ipc_channel_reader.h b/chromium/ipc/ipc_channel_reader.h index 9c398bdce35..130384659fc 100644 --- a/chromium/ipc/ipc_channel_reader.h +++ b/chromium/ipc/ipc_channel_reader.h @@ -42,8 +42,12 @@ class ChannelReader { // data. See ReadData for more. bool AsyncReadComplete(int bytes_read); - // Returns true if the given message is the "hello" message sent on channel - // set-up. + // Returns true if the given message is internal to the IPC implementation, + // like the "hello" message sent on channel set-up. + bool IsInternalMessage(const Message& m) const; + + // Returns true if the given message is an Hello message + // sent on channel set-up. bool IsHelloMessage(const Message& m) const; protected: @@ -76,8 +80,8 @@ class ChannelReader { // though there could be more data ready to be read from the OS. virtual bool DidEmptyInputBuffers() = 0; - // Handles the first message sent over the pipe which contains setup info. - virtual void HandleHelloMessage(const Message& msg) = 0; + // Handles internal messages, like the hello message sent on channel startup. + virtual void HandleInternalMessage(const Message& msg) = 0; private: // Takes the given data received from the IPC channel and dispatches any diff --git a/chromium/ipc/ipc_channel_win.cc b/chromium/ipc/ipc_channel_win.cc index 6d7cfe8d3f4..8c08500355e 100644 --- a/chromium/ipc/ipc_channel_win.cc +++ b/chromium/ipc/ipc_channel_win.cc @@ -152,7 +152,8 @@ bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { return true; } -void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { +void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) { + DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE)); // The hello message contains one parameter containing the PID. PickleIterator it(msg); int32 claimed_pid; diff --git a/chromium/ipc/ipc_channel_win.h b/chromium/ipc/ipc_channel_win.h index 711f57fde72..a544f8be4bb 100644 --- a/chromium/ipc/ipc_channel_win.h +++ b/chromium/ipc/ipc_channel_win.h @@ -41,7 +41,7 @@ class Channel::ChannelImpl : public internal::ChannelReader, int* bytes_read) OVERRIDE; virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE; bool DidEmptyInputBuffers() OVERRIDE; - virtual void HandleHelloMessage(const Message& msg) OVERRIDE; + virtual void HandleInternalMessage(const Message& msg) OVERRIDE; static const string16 PipeName(const std::string& channel_id, int32* secret); diff --git a/chromium/ipc/ipc_descriptors.h b/chromium/ipc/ipc_descriptors.h index b766bbbe769..9dcff8ceb13 100644 --- a/chromium/ipc/ipc_descriptors.h +++ b/chromium/ipc/ipc_descriptors.h @@ -9,6 +9,10 @@ // base::GlobalDescriptors object (see base/posix/global_descriptors.h) enum { kPrimaryIPCChannel = 0, + kStatsTableSharedMemFd, + + // The first key that can be use to register descriptors. + kIPCDescriptorMax }; #endif // IPC_IPC_DESCRIPTORS_H_ diff --git a/chromium/ipc/ipc_message_macros.h b/chromium/ipc/ipc_message_macros.h index cd036802528..c4e250cf9e6 100644 --- a/chromium/ipc/ipc_message_macros.h +++ b/chromium/ipc/ipc_message_macros.h @@ -202,7 +202,7 @@ #include "ipc/ipc_message_utils_impl.h" #endif -// Convenience macro for defining structs without inheritence. Should not need +// Convenience macro for defining structs without inheritance. Should not need // to be subsequently redefined. #define IPC_STRUCT_BEGIN(struct_name) \ IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, IPC::NoParams) @@ -996,8 +996,8 @@ ipc_message__.type()) #define IPC_END_MESSAGE_MAP() \ - DCHECK(msg_is_ok__); \ } \ + DCHECK(msg_is_ok__); \ } #define IPC_END_MESSAGE_MAP_EX() \ @@ -1010,7 +1010,14 @@ #endif // IPC_IPC_MESSAGE_MACROS_H_ +// The following #ifdef cannot be removed. Although the code is semantically +// equivalent without the #ifdef, VS2013 contains a bug where it is +// over-aggressive in optimizing out #includes. Putting the #ifdef is a +// workaround for this bug. See http://goo.gl/eGt2Fb for more details. +// This can be removed once VS2013 is fixed. +#ifdef IPC_MESSAGE_START // Clean up IPC_MESSAGE_START in this unguarded section so that the // XXX_messages.h files need not do so themselves. This makes the // XXX_messages.h files easier to write. #undef IPC_MESSAGE_START +#endif diff --git a/chromium/ipc/ipc_message_start.h b/chromium/ipc/ipc_message_start.h index 314ed0e4689..3016f5d3461 100644 --- a/chromium/ipc/ipc_message_start.h +++ b/chromium/ipc/ipc_message_start.h @@ -11,6 +11,7 @@ enum IPCMessageStart { AutomationMsgStart = 0, QtMsgStart, + FrameMsgStart, ViewMsgStart, InputMsgStart, PluginMsgStart, @@ -91,6 +92,7 @@ enum IPCMessageStart { PowerMonitorMsgStart, EncryptedMediaMsgStart, ServiceWorkerMsgStart, + MessagePortMsgStart, LastIPCMsgStart // Must come last. }; diff --git a/chromium/ipc/ipc_message_utils.cc b/chromium/ipc/ipc_message_utils.cc index 2acddceb51c..0390648f457 100644 --- a/chromium/ipc/ipc_message_utils.cc +++ b/chromium/ipc/ipc_message_utils.cc @@ -311,37 +311,18 @@ void ParamTraits<unsigned long long>::Log(const param_type& p, std::string* l) { l->append(base::Uint64ToString(p)); } -void ParamTraits<float>::Write(Message* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type)); -} - -bool ParamTraits<float>::Read(const Message* m, PickleIterator* iter, - param_type* r) { - const char *data; - int data_size; - if (!m->ReadData(iter, &data, &data_size) || - data_size != sizeof(param_type)) { - NOTREACHED(); - return false; - } - memcpy(r, data, sizeof(param_type)); - return true; -} - void ParamTraits<float>::Log(const param_type& p, std::string* l) { l->append(base::StringPrintf("%e", p)); } void ParamTraits<double>::Write(Message* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type)); + m->WriteBytes(reinterpret_cast<const char*>(&p), sizeof(param_type)); } bool ParamTraits<double>::Read(const Message* m, PickleIterator* iter, param_type* r) { const char *data; - int data_size; - if (!m->ReadData(iter, &data, &data_size) || - data_size != sizeof(param_type)) { + if (!m->ReadBytes(iter, &data, sizeof(*r))) { NOTREACHED(); return false; } @@ -363,7 +344,7 @@ void ParamTraits<std::wstring>::Log(const param_type& p, std::string* l) { } #if !defined(WCHAR_T_IS_UTF16) -void ParamTraits<string16>::Log(const param_type& p, std::string* l) { +void ParamTraits<base::string16>::Log(const param_type& p, std::string* l) { l->append(UTF16ToUTF8(p)); } #endif @@ -555,7 +536,7 @@ void ParamTraits<base::NullableString16>::Write(Message* m, bool ParamTraits<base::NullableString16>::Read(const Message* m, PickleIterator* iter, param_type* r) { - string16 string; + base::string16 string; if (!ReadParam(m, iter, &string)) return false; bool is_null; diff --git a/chromium/ipc/ipc_message_utils.h b/chromium/ipc/ipc_message_utils.h index 7121c19e304..24b38af68ee 100644 --- a/chromium/ipc/ipc_message_utils.h +++ b/chromium/ipc/ipc_message_utils.h @@ -216,8 +216,12 @@ struct ParamTraits<unsigned long long> { template <> struct IPC_EXPORT ParamTraits<float> { typedef float param_type; - static void Write(Message* m, const param_type& p); - static bool Read(const Message* m, PickleIterator* iter, param_type* r); + static void Write(Message* m, const param_type& p) { + m->WriteFloat(p); + } + static bool Read(const Message* m, PickleIterator* iter, param_type* r) { + return m->ReadFloat(iter, r); + } static void Log(const param_type& p, std::string* l); }; @@ -261,8 +265,8 @@ struct ParamTraits<std::wstring> { // need this trait. #if !defined(WCHAR_T_IS_UTF16) template <> -struct ParamTraits<string16> { - typedef string16 param_type; +struct ParamTraits<base::string16> { + typedef base::string16 param_type; static void Write(Message* m, const param_type& p) { m->WriteString16(p); } diff --git a/chromium/ipc/ipc_send_fds_test.cc b/chromium/ipc/ipc_send_fds_test.cc index 4cddc1c2274..aeec8907a4f 100644 --- a/chromium/ipc/ipc_send_fds_test.cc +++ b/chromium/ipc/ipc_send_fds_test.cc @@ -11,13 +11,18 @@ extern "C" { } #endif #include <fcntl.h> +#include <sys/socket.h> #include <sys/stat.h> #include <unistd.h> +#include <queue> + +#include "base/callback.h" #include "base/file_descriptor_posix.h" #include "base/message_loop/message_loop.h" #include "base/pickle.h" #include "base/posix/eintr_wrapper.h" +#include "base/synchronization/waitable_event.h" #include "ipc/ipc_message_utils.h" #include "ipc/ipc_test_base.h" @@ -26,57 +31,67 @@ namespace { const unsigned kNumFDsToSend = 20; const char* kDevZeroPath = "/dev/zero"; -static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) { - // Check that we can read from the FD. - char buf; - ssize_t amt_read = read(fd, &buf, 1); - ASSERT_EQ(amt_read, 1); - ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes. - - struct stat st; - ASSERT_EQ(fstat(fd, &st), 0); - - ASSERT_EQ(close(fd), 0); - - // Compare inode numbers to check that the file sent over the wire is actually - // the one expected. - ASSERT_EQ(inode_num, st.st_ino); -} - -class MyChannelDescriptorListener : public IPC::Listener { +class MyChannelDescriptorListenerBase : public IPC::Listener { public: - explicit MyChannelDescriptorListener(ino_t expected_inode_num) - : expected_inode_num_(expected_inode_num), - num_fds_received_(0) {} - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { PickleIterator iter(message); - ++num_fds_received_; base::FileDescriptor descriptor; IPC::ParamTraits<base::FileDescriptor>::Read(&message, &iter, &descriptor); - VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_); - if (num_fds_received_ == kNumFDsToSend) - base::MessageLoop::current()->Quit(); - + HandleFD(descriptor.fd); return true; } - virtual void OnChannelError() OVERRIDE { - base::MessageLoop::current()->Quit(); + protected: + virtual void HandleFD(int fd) = 0; +}; + +class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase { + public: + explicit MyChannelDescriptorListener(ino_t expected_inode_num) + : MyChannelDescriptorListenerBase(), + expected_inode_num_(expected_inode_num), + num_fds_received_(0) { } bool GotExpectedNumberOfDescriptors() const { return num_fds_received_ == kNumFDsToSend; } + virtual void OnChannelError() OVERRIDE { + base::MessageLoop::current()->Quit(); + } + + protected: + virtual void HandleFD(int fd) OVERRIDE { + // Check that we can read from the FD. + char buf; + ssize_t amt_read = read(fd, &buf, 1); + ASSERT_EQ(amt_read, 1); + ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes. + + struct stat st; + ASSERT_EQ(fstat(fd, &st), 0); + + ASSERT_EQ(close(fd), 0); + + // Compare inode numbers to check that the file sent over the wire is + // actually the one expected. + ASSERT_EQ(expected_inode_num_, st.st_ino); + + ++num_fds_received_; + if (num_fds_received_ == kNumFDsToSend) + base::MessageLoop::current()->Quit(); + } + private: ino_t expected_inode_num_; unsigned num_fds_received_; }; + class IPCSendFdsTest : public IPCTestBase { protected: void RunServer() { @@ -138,7 +153,7 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsClient) { struct stat st; int fd = open(kDevZeroPath, O_RDONLY); fstat(fd, &st); - EXPECT_GE(HANDLE_EINTR(close(fd)), 0); + EXPECT_GE(IGNORE_EINTR(close(fd)), 0); return SendFdsClientCommon("SendFdsClient", st.st_ino); } @@ -154,7 +169,7 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) { struct stat st; const int fd = open(kDevZeroPath, O_RDONLY); fstat(fd, &st); - if (HANDLE_EINTR(close(fd)) < 0) + if (IGNORE_EINTR(close(fd)) < 0) return -1; // Enable the sandbox. @@ -178,6 +193,188 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) { } #endif // defined(OS_MACOSX) + +class MyCBListener : public MyChannelDescriptorListenerBase { + public: + MyCBListener(base::Callback<void(int)> cb, int fds_to_send) + : MyChannelDescriptorListenerBase(), + cb_(cb) { + } + + protected: + virtual void HandleFD(int fd) OVERRIDE { + cb_.Run(fd); + } + private: + base::Callback<void(int)> cb_; +}; + +std::pair<int, int> make_socket_pair() { + int pipe_fds[2]; + CHECK_EQ(0, HANDLE_EINTR(socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds))); + return std::pair<int, int>(pipe_fds[0], pipe_fds[1]); +} + +static void null_cb(int unused_fd) { + NOTREACHED(); +} + +class PipeChannelHelper { + public: + PipeChannelHelper(base::Thread* in_thread, + base::Thread* out_thread, + base::Callback<void(int)> cb, + int fds_to_send) : + in_thread_(in_thread), + out_thread_(out_thread), + cb_listener_(cb, fds_to_send), + null_listener_(base::Bind(&null_cb), 0) { + } + + void Init() { + IPC::ChannelHandle in_handle("IN"); + in.reset(new IPC::Channel(in_handle, + IPC::Channel::MODE_SERVER, + &null_listener_)); + base::FileDescriptor out_fd(in->TakeClientFileDescriptor(), false); + IPC::ChannelHandle out_handle("OUT", out_fd); + out.reset(new IPC::Channel(out_handle, + IPC::Channel::MODE_CLIENT, + &cb_listener_)); + // PostTask the connect calls to make sure the callbacks happens + // on the right threads. + in_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&PipeChannelHelper::Connect, in.get())); + out_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&PipeChannelHelper::Connect, out.get())); + } + + static void DestroyChannel(scoped_ptr<IPC::Channel> *c, + base::WaitableEvent *event) { + c->reset(0); + event->Signal(); + } + + ~PipeChannelHelper() { + base::WaitableEvent a(true, false); + base::WaitableEvent b(true, false); + in_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&PipeChannelHelper::DestroyChannel, &in, &a)); + out_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&PipeChannelHelper::DestroyChannel, &out, &b)); + a.Wait(); + b.Wait(); + } + + static void Connect(IPC::Channel *channel) { + EXPECT_TRUE(channel->Connect()); + } + + void Send(int fd) { + CHECK_EQ(base::MessageLoop::current(), in_thread_->message_loop()); + + ASSERT_GE(fd, 0); + base::FileDescriptor descriptor(fd, true); + + IPC::Message* message = + new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor); + ASSERT_TRUE(in->Send(message)); + } + + private: + scoped_ptr<IPC::Channel> in, out; + base::Thread* in_thread_; + base::Thread* out_thread_; + MyCBListener cb_listener_; + MyCBListener null_listener_; +}; + +// This test is meant to provoke a kernel bug on OSX, and to prove +// that the workaround for it is working. It sets up two pipes and three +// threads, the producer thread creates socketpairs and sends one of the fds +// over pipe1 to the middleman thread. The middleman thread simply takes the fd +// sends it over pipe2 to the consumer thread. The consumer thread writes a byte +// to each fd it receives and then closes the pipe. The producer thread reads +// the bytes back from each pair of pipes and make sure that everything worked. +// This feedback mechanism makes sure that not too many file descriptors are +// in flight at the same time. For more info on the bug, see: +// http://crbug.com/298276 +class IPCMultiSendingFdsTest : public testing::Test { + public: + IPCMultiSendingFdsTest() : received_(true, false) {} + + void Producer(PipeChannelHelper* dest, + base::Thread* t, + int pipes_to_send) { + for (int i = 0; i < pipes_to_send; i++) { + received_.Reset(); + std::pair<int, int> pipe_fds = make_socket_pair(); + t->message_loop()->PostTask( + FROM_HERE, + base::Bind(&PipeChannelHelper::Send, + base::Unretained(dest), + pipe_fds.second)); + char tmp = 'x'; + CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds.first, &tmp, 1))); + CHECK_EQ(0, IGNORE_EINTR(close(pipe_fds.first))); + received_.Wait(); + } + } + + void ConsumerHandleFD(int fd) { + char tmp = 'y'; + CHECK_EQ(1, HANDLE_EINTR(read(fd, &tmp, 1))); + CHECK_EQ(tmp, 'x'); + CHECK_EQ(0, IGNORE_EINTR(close(fd))); + received_.Signal(); + } + + base::Thread* CreateThread(const char* name) { + base::Thread* ret = new base::Thread(name); + base::Thread::Options options; + options.message_loop_type = base::MessageLoop::TYPE_IO; + ret->StartWithOptions(options); + return ret; + } + + void Run() { + // On my mac, this test fails roughly 35 times per + // million sends with low load, but much more with high load. + // Unless the workaround is in place. With 10000 sends, we + // should see at least a 3% failure rate. + const int pipes_to_send = 20000; + scoped_ptr<base::Thread> producer(CreateThread("producer")); + scoped_ptr<base::Thread> middleman(CreateThread("middleman")); + scoped_ptr<base::Thread> consumer(CreateThread("consumer")); + PipeChannelHelper pipe1( + middleman.get(), + consumer.get(), + base::Bind(&IPCMultiSendingFdsTest::ConsumerHandleFD, + base::Unretained(this)), + pipes_to_send); + PipeChannelHelper pipe2( + producer.get(), + middleman.get(), + base::Bind(&PipeChannelHelper::Send, base::Unretained(&pipe1)), + pipes_to_send); + pipe1.Init(); + pipe2.Init(); + Producer(&pipe2, producer.get(), pipes_to_send); + } + + private: + base::WaitableEvent received_; +}; + +TEST_F(IPCMultiSendingFdsTest, StressTest) { + Run(); +} + } // namespace #endif // defined(OS_POSIX) diff --git a/chromium/ipc/run_all_unittests.cc b/chromium/ipc/run_all_unittests.cc new file mode 100644 index 00000000000..d36f8712210 --- /dev/null +++ b/chromium/ipc/run_all_unittests.cc @@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/bind.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" + +#if defined(OS_ANDROID) +#include "base/android/jni_android.h" +#include "base/test/test_file_util.h" +#endif + +namespace { + +class NoAtExitBaseTestSuite : public base::TestSuite { + public: + NoAtExitBaseTestSuite(int argc, char** argv) + : base::TestSuite(argc, argv, false) { + } +}; + +int RunTestSuite(int argc, char** argv) { + return NoAtExitBaseTestSuite(argc, argv).Run(); +} + +} // namespace + +int main(int argc, char** argv) { +#if defined(OS_ANDROID) + JNIEnv* env = base::android::AttachCurrentThread(); + file_util::RegisterContentUriTestUtils(env); +#else + base::AtExitManager at_exit; +#endif + return base::LaunchUnitTestsSerially(argc, + argv, + base::Bind(&RunTestSuite, argc, argv)); +} diff --git a/chromium/ipc/unix_domain_socket_util.cc b/chromium/ipc/unix_domain_socket_util.cc index 7f513a3ab48..10df9b21441 100644 --- a/chromium/ipc/unix_domain_socket_util.cc +++ b/chromium/ipc/unix_domain_socket_util.cc @@ -84,7 +84,7 @@ bool CreateServerUnixDomainSocket(const base::FilePath& socket_path, file_util::ScopedFD scoped_fd(&fd); // Make sure the path we need exists. - if (!file_util::CreateDirectory(socket_dir)) { + if (!base::CreateDirectory(socket_dir)) { LOG(ERROR) << "Couldn't create directory: " << socket_dir.value(); return false; } |