| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/system/channel.h" | 5 #include "mojo/system/channel.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 } | 29 } |
| 30 | 30 |
| 31 Channel::EndpointInfo::EndpointInfo(scoped_refptr<MessagePipe> message_pipe, | 31 Channel::EndpointInfo::EndpointInfo(scoped_refptr<MessagePipe> message_pipe, |
| 32 unsigned port) | 32 unsigned port) |
| 33 : state(STATE_NORMAL), message_pipe(message_pipe), port(port) { | 33 : state(STATE_NORMAL), message_pipe(message_pipe), port(port) { |
| 34 } | 34 } |
| 35 | 35 |
| 36 Channel::EndpointInfo::~EndpointInfo() { | 36 Channel::EndpointInfo::~EndpointInfo() { |
| 37 } | 37 } |
| 38 | 38 |
| 39 Channel::Channel() : is_running_(false), next_local_id_(kBootstrapEndpointId) { | 39 Channel::Channel() |
| 40 : is_running_(false), |
| 41 is_shutting_down_(false), |
| 42 next_local_id_(kBootstrapEndpointId) { |
| 40 } | 43 } |
| 41 | 44 |
| 42 bool Channel::Init(scoped_ptr<RawChannel> raw_channel) { | 45 bool Channel::Init(scoped_ptr<RawChannel> raw_channel) { |
| 43 DCHECK(creation_thread_checker_.CalledOnValidThread()); | 46 DCHECK(creation_thread_checker_.CalledOnValidThread()); |
| 44 DCHECK(raw_channel); | 47 DCHECK(raw_channel); |
| 45 | 48 |
| 46 // No need to take |lock_|, since this must be called before this object | 49 // No need to take |lock_|, since this must be called before this object |
| 47 // becomes thread-safe. | 50 // becomes thread-safe. |
| 48 DCHECK(!is_running_no_lock()); | 51 DCHECK(!is_running_); |
| 49 raw_channel_ = raw_channel.Pass(); | 52 raw_channel_ = raw_channel.Pass(); |
| 50 | 53 |
| 51 if (!raw_channel_->Init(this)) { | 54 if (!raw_channel_->Init(this)) { |
| 52 raw_channel_.reset(); | 55 raw_channel_.reset(); |
| 53 return false; | 56 return false; |
| 54 } | 57 } |
| 55 | 58 |
| 56 is_running_ = true; | 59 is_running_ = true; |
| 57 return true; | 60 return true; |
| 58 } | 61 } |
| 59 | 62 |
| 60 void Channel::Shutdown() { | 63 void Channel::Shutdown() { |
| 61 DCHECK(creation_thread_checker_.CalledOnValidThread()); | 64 DCHECK(creation_thread_checker_.CalledOnValidThread()); |
| 62 | 65 |
| 63 IdToEndpointInfoMap to_destroy; | 66 IdToEndpointInfoMap to_destroy; |
| 64 { | 67 { |
| 65 base::AutoLock locker(lock_); | 68 base::AutoLock locker(lock_); |
| 66 if (!is_running_no_lock()) | 69 if (!is_running_) |
| 67 return; | 70 return; |
| 68 | 71 |
| 69 // Note: Don't reset |raw_channel_|, in case we're being called from within | 72 // Note: Don't reset |raw_channel_|, in case we're being called from within |
| 70 // |OnReadMessage()| or |OnError()|. | 73 // |OnReadMessage()| or |OnError()|. |
| 71 raw_channel_->Shutdown(); | 74 raw_channel_->Shutdown(); |
| 72 is_running_ = false; | 75 is_running_ = false; |
| 73 | 76 |
| 74 // We need to deal with it outside the lock. | 77 // We need to deal with it outside the lock. |
| 75 std::swap(to_destroy, local_id_to_endpoint_info_map_); | 78 std::swap(to_destroy, local_id_to_endpoint_info_map_); |
| 76 } | 79 } |
| 77 | 80 |
| 78 size_t num_live = 0; | 81 size_t num_live = 0; |
| 79 size_t num_zombies = 0; | 82 size_t num_zombies = 0; |
| 80 for (IdToEndpointInfoMap::iterator it = to_destroy.begin(); | 83 for (IdToEndpointInfoMap::iterator it = to_destroy.begin(); |
| 81 it != to_destroy.end(); | 84 it != to_destroy.end(); |
| 82 ++it) { | 85 ++it) { |
| 83 if (it->second.state == EndpointInfo::STATE_NORMAL) { | 86 if (it->second.state == EndpointInfo::STATE_NORMAL) { |
| 84 it->second.message_pipe->OnRemove(it->second.port); | 87 it->second.message_pipe->OnRemove(it->second.port); |
| 85 num_live++; | 88 num_live++; |
| 86 } else { | 89 } else { |
| 87 DCHECK(!it->second.message_pipe); | 90 DCHECK(!it->second.message_pipe); |
| 88 num_zombies++; | 91 num_zombies++; |
| 89 } | 92 } |
| 90 } | 93 } |
| 91 DVLOG_IF(2, num_live || num_zombies) << "Shut down Channel with " << num_live | 94 DVLOG_IF(2, num_live || num_zombies) << "Shut down Channel with " << num_live |
| 92 << " live endpoints and " << num_zombies | 95 << " live endpoints and " << num_zombies |
| 93 << " zombies"; | 96 << " zombies"; |
| 94 } | 97 } |
| 95 | 98 |
| 99 void Channel::WillShutdownSoon() { |
| 100 base::AutoLock locker(lock_); |
| 101 is_shutting_down_ = true; |
| 102 } |
| 103 |
| 96 MessageInTransit::EndpointId Channel::AttachMessagePipeEndpoint( | 104 MessageInTransit::EndpointId Channel::AttachMessagePipeEndpoint( |
| 97 scoped_refptr<MessagePipe> message_pipe, | 105 scoped_refptr<MessagePipe> message_pipe, |
| 98 unsigned port) { | 106 unsigned port) { |
| 99 DCHECK(message_pipe); | 107 DCHECK(message_pipe); |
| 100 DCHECK(port == 0 || port == 1); | 108 DCHECK(port == 0 || port == 1); |
| 101 | 109 |
| 102 MessageInTransit::EndpointId local_id; | 110 MessageInTransit::EndpointId local_id; |
| 103 { | 111 { |
| 104 base::AutoLock locker(lock_); | 112 base::AutoLock locker(lock_); |
| 105 | 113 |
| 114 DLOG_IF(WARNING, is_shutting_down_) |
| 115 << "AttachMessagePipeEndpoint() while shutting down"; |
| 116 |
| 106 while (next_local_id_ == MessageInTransit::kInvalidEndpointId || | 117 while (next_local_id_ == MessageInTransit::kInvalidEndpointId || |
| 107 local_id_to_endpoint_info_map_.find(next_local_id_) != | 118 local_id_to_endpoint_info_map_.find(next_local_id_) != |
| 108 local_id_to_endpoint_info_map_.end()) | 119 local_id_to_endpoint_info_map_.end()) |
| 109 next_local_id_++; | 120 next_local_id_++; |
| 110 | 121 |
| 111 local_id = next_local_id_; | 122 local_id = next_local_id_; |
| 112 next_local_id_++; | 123 next_local_id_++; |
| 113 | 124 |
| 114 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll avoid | 125 // TODO(vtl): Use emplace when we move to C++11 unordered_maps. (It'll avoid |
| 115 // some expensive reference count increment/decrements.) Once this is done, | 126 // some expensive reference count increment/decrements.) Once this is done, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 144 } | 155 } |
| 145 return MessageInTransit::kInvalidEndpointId; | 156 return MessageInTransit::kInvalidEndpointId; |
| 146 } | 157 } |
| 147 | 158 |
| 148 bool Channel::RunMessagePipeEndpoint(MessageInTransit::EndpointId local_id, | 159 bool Channel::RunMessagePipeEndpoint(MessageInTransit::EndpointId local_id, |
| 149 MessageInTransit::EndpointId remote_id) { | 160 MessageInTransit::EndpointId remote_id) { |
| 150 EndpointInfo endpoint_info; | 161 EndpointInfo endpoint_info; |
| 151 { | 162 { |
| 152 base::AutoLock locker(lock_); | 163 base::AutoLock locker(lock_); |
| 153 | 164 |
| 165 DLOG_IF(WARNING, is_shutting_down_) |
| 166 << "RunMessagePipeEndpoint() while shutting down"; |
| 167 |
| 154 IdToEndpointInfoMap::const_iterator it = | 168 IdToEndpointInfoMap::const_iterator it = |
| 155 local_id_to_endpoint_info_map_.find(local_id); | 169 local_id_to_endpoint_info_map_.find(local_id); |
| 156 if (it == local_id_to_endpoint_info_map_.end()) | 170 if (it == local_id_to_endpoint_info_map_.end()) |
| 157 return false; | 171 return false; |
| 158 endpoint_info = it->second; | 172 endpoint_info = it->second; |
| 159 } | 173 } |
| 160 | 174 |
| 161 // Assume that this was in response to |kSubtypeChannelRunMessagePipeEndpoint| | 175 // Assume that this was in response to |kSubtypeChannelRunMessagePipeEndpoint| |
| 162 // and ignore it. | 176 // and ignore it. |
| 163 if (endpoint_info.state != EndpointInfo::STATE_NORMAL) { | 177 if (endpoint_info.state != EndpointInfo::STATE_NORMAL) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 190 HandleLocalError(base::StringPrintf( | 204 HandleLocalError(base::StringPrintf( |
| 191 "Failed to send message to run remote message pipe endpoint (local ID " | 205 "Failed to send message to run remote message pipe endpoint (local ID " |
| 192 "%u, remote ID %u)", | 206 "%u, remote ID %u)", |
| 193 static_cast<unsigned>(local_id), | 207 static_cast<unsigned>(local_id), |
| 194 static_cast<unsigned>(remote_id))); | 208 static_cast<unsigned>(remote_id))); |
| 195 } | 209 } |
| 196 } | 210 } |
| 197 | 211 |
| 198 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { | 212 bool Channel::WriteMessage(scoped_ptr<MessageInTransit> message) { |
| 199 base::AutoLock locker(lock_); | 213 base::AutoLock locker(lock_); |
| 200 if (!is_running_no_lock()) { | 214 if (!is_running_) { |
| 201 // TODO(vtl): I think this is probably not an error condition, but I should | 215 // TODO(vtl): I think this is probably not an error condition, but I should |
| 202 // think about it (and the shutdown sequence) more carefully. | 216 // think about it (and the shutdown sequence) more carefully. |
| 203 LOG(WARNING) << "WriteMessage() after shutdown"; | 217 LOG(WARNING) << "WriteMessage() after shutdown"; |
| 204 return false; | 218 return false; |
| 205 } | 219 } |
| 206 | 220 |
| 221 DLOG_IF(WARNING, is_shutting_down_) << "WriteMessage() while shutting down"; |
| 207 return raw_channel_->WriteMessage(message.Pass()); | 222 return raw_channel_->WriteMessage(message.Pass()); |
| 208 } | 223 } |
| 209 | 224 |
| 210 bool Channel::IsWriteBufferEmpty() { | 225 bool Channel::IsWriteBufferEmpty() { |
| 211 base::AutoLock locker(lock_); | 226 base::AutoLock locker(lock_); |
| 212 if (!is_running_no_lock()) | 227 if (!is_running_) |
| 213 return true; | 228 return true; |
| 214 return raw_channel_->IsWriteBufferEmpty(); | 229 return raw_channel_->IsWriteBufferEmpty(); |
| 215 } | 230 } |
| 216 | 231 |
| 217 void Channel::DetachMessagePipeEndpoint( | 232 void Channel::DetachMessagePipeEndpoint( |
| 218 MessageInTransit::EndpointId local_id, | 233 MessageInTransit::EndpointId local_id, |
| 219 MessageInTransit::EndpointId remote_id) { | 234 MessageInTransit::EndpointId remote_id) { |
| 220 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); | 235 DCHECK_NE(local_id, MessageInTransit::kInvalidEndpointId); |
| 221 | 236 |
| 222 bool should_send_remove_message = false; | 237 bool should_send_remove_message = false; |
| 223 { | 238 { |
| 224 base::AutoLock locker_(lock_); | 239 base::AutoLock locker_(lock_); |
| 225 if (!is_running_no_lock()) | 240 if (!is_running_) |
| 226 return; | 241 return; |
| 227 | 242 |
| 228 IdToEndpointInfoMap::iterator it = | 243 IdToEndpointInfoMap::iterator it = |
| 229 local_id_to_endpoint_info_map_.find(local_id); | 244 local_id_to_endpoint_info_map_.find(local_id); |
| 230 DCHECK(it != local_id_to_endpoint_info_map_.end()); | 245 DCHECK(it != local_id_to_endpoint_info_map_.end()); |
| 231 | 246 |
| 232 switch (it->second.state) { | 247 switch (it->second.state) { |
| 233 case EndpointInfo::STATE_NORMAL: | 248 case EndpointInfo::STATE_NORMAL: |
| 234 it->second.state = EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK; | 249 it->second.state = EndpointInfo::STATE_WAIT_REMOTE_REMOVE_ACK; |
| 235 it->second.message_pipe = NULL; | 250 it->second.message_pipe = NULL; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 261 static_cast<unsigned>(remote_id))); | 276 static_cast<unsigned>(remote_id))); |
| 262 } | 277 } |
| 263 } | 278 } |
| 264 | 279 |
| 265 size_t Channel::GetSerializedPlatformHandleSize() const { | 280 size_t Channel::GetSerializedPlatformHandleSize() const { |
| 266 return raw_channel_->GetSerializedPlatformHandleSize(); | 281 return raw_channel_->GetSerializedPlatformHandleSize(); |
| 267 } | 282 } |
| 268 | 283 |
| 269 Channel::~Channel() { | 284 Channel::~Channel() { |
| 270 // The channel should have been shut down first. | 285 // The channel should have been shut down first. |
| 271 DCHECK(!is_running_no_lock()); | 286 DCHECK(!is_running_); |
| 272 } | 287 } |
| 273 | 288 |
| 274 void Channel::OnReadMessage( | 289 void Channel::OnReadMessage( |
| 275 const MessageInTransit::View& message_view, | 290 const MessageInTransit::View& message_view, |
| 276 embedder::ScopedPlatformHandleVectorPtr platform_handles) { | 291 embedder::ScopedPlatformHandleVectorPtr platform_handles) { |
| 277 switch (message_view.type()) { | 292 switch (message_view.type()) { |
| 278 case MessageInTransit::kTypeMessagePipeEndpoint: | 293 case MessageInTransit::kTypeMessagePipeEndpoint: |
| 279 case MessageInTransit::kTypeMessagePipe: | 294 case MessageInTransit::kTypeMessagePipe: |
| 280 OnReadMessageForDownstream(message_view, platform_handles.Pass()); | 295 OnReadMessageForDownstream(message_view, platform_handles.Pass()); |
| 281 break; | 296 break; |
| 282 case MessageInTransit::kTypeChannel: | 297 case MessageInTransit::kTypeChannel: |
| 283 OnReadMessageForChannel(message_view, platform_handles.Pass()); | 298 OnReadMessageForChannel(message_view, platform_handles.Pass()); |
| 284 break; | 299 break; |
| 285 default: | 300 default: |
| 286 HandleRemoteError( | 301 HandleRemoteError( |
| 287 base::StringPrintf("Received message of invalid type %u", | 302 base::StringPrintf("Received message of invalid type %u", |
| 288 static_cast<unsigned>(message_view.type()))); | 303 static_cast<unsigned>(message_view.type()))); |
| 289 break; | 304 break; |
| 290 } | 305 } |
| 291 } | 306 } |
| 292 | 307 |
| 293 void Channel::OnError(Error error) { | 308 void Channel::OnError(Error error) { |
| 294 switch (error) { | 309 switch (error) { |
| 295 case ERROR_READ_SHUTDOWN: | 310 case ERROR_READ_SHUTDOWN: |
| 296 // The other side was cleanly closed, so this isn't actually an error. | 311 // The other side was cleanly closed, so this isn't actually an error. |
| 297 DVLOG(1) << "RawChannel read error (shutdown)"; | 312 DVLOG(1) << "RawChannel read error (shutdown)"; |
| 298 break; | 313 break; |
| 299 case ERROR_READ_BROKEN: | 314 case ERROR_READ_BROKEN: { |
| 300 LOG(ERROR) << "RawChannel read error (connection broken)"; | 315 base::AutoLock locker(lock_); |
| 316 LOG_IF(ERROR, !is_shutting_down_) |
| 317 << "RawChannel read error (connection broken)"; |
| 301 break; | 318 break; |
| 319 } |
| 302 case ERROR_READ_BAD_MESSAGE: | 320 case ERROR_READ_BAD_MESSAGE: |
| 303 // Receiving a bad message means either a bug, data corruption, or | 321 // Receiving a bad message means either a bug, data corruption, or |
| 304 // malicious attack (probably due to some other bug). | 322 // malicious attack (probably due to some other bug). |
| 305 LOG(ERROR) << "RawChannel read error (received bad message)"; | 323 LOG(ERROR) << "RawChannel read error (received bad message)"; |
| 306 break; | 324 break; |
| 307 case ERROR_READ_UNKNOWN: | 325 case ERROR_READ_UNKNOWN: |
| 308 LOG(ERROR) << "RawChannel read error (unknown)"; | 326 LOG(ERROR) << "RawChannel read error (unknown)"; |
| 309 break; | 327 break; |
| 310 case ERROR_WRITE: | 328 case ERROR_WRITE: |
| 311 // Write errors are slightly notable: they probably shouldn't happen under | 329 // Write errors are slightly notable: they probably shouldn't happen under |
| (...skipping 16 matching lines...) Expand all Loading... |
| 328 return; | 346 return; |
| 329 } | 347 } |
| 330 | 348 |
| 331 EndpointInfo endpoint_info; | 349 EndpointInfo endpoint_info; |
| 332 { | 350 { |
| 333 base::AutoLock locker(lock_); | 351 base::AutoLock locker(lock_); |
| 334 | 352 |
| 335 // Since we own |raw_channel_|, and this method and |Shutdown()| should only | 353 // Since we own |raw_channel_|, and this method and |Shutdown()| should only |
| 336 // be called from the creation thread, |raw_channel_| should never be null | 354 // be called from the creation thread, |raw_channel_| should never be null |
| 337 // here. | 355 // here. |
| 338 DCHECK(is_running_no_lock()); | 356 DCHECK(is_running_); |
| 339 | 357 |
| 340 IdToEndpointInfoMap::const_iterator it = | 358 IdToEndpointInfoMap::const_iterator it = |
| 341 local_id_to_endpoint_info_map_.find(local_id); | 359 local_id_to_endpoint_info_map_.find(local_id); |
| 342 if (it == local_id_to_endpoint_info_map_.end()) { | 360 if (it == local_id_to_endpoint_info_map_.end()) { |
| 343 HandleRemoteError(base::StringPrintf( | 361 HandleRemoteError(base::StringPrintf( |
| 344 "Received a message for nonexistent local destination ID %u", | 362 "Received a message for nonexistent local destination ID %u", |
| 345 static_cast<unsigned>(local_id))); | 363 static_cast<unsigned>(local_id))); |
| 346 // This is strongly indicative of some problem. However, it's not a fatal | 364 // This is strongly indicative of some problem. However, it's not a fatal |
| 347 // error, since it may indicate a bug (or hostile) remote process. Don't | 365 // error, since it may indicate a bug (or hostile) remote process. Don't |
| 348 // die even for Debug builds, since handling this properly needs to be | 366 // die even for Debug builds, since handling this properly needs to be |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 // TODO(vtl): Is this how we really want to handle this? | 523 // TODO(vtl): Is this how we really want to handle this? |
| 506 // Sometimes we'll want to propagate the error back to the message pipe | 524 // Sometimes we'll want to propagate the error back to the message pipe |
| 507 // (endpoint), and notify it that the remote is (effectively) closed. | 525 // (endpoint), and notify it that the remote is (effectively) closed. |
| 508 // Sometimes we'll want to kill the channel (and notify all the endpoints that | 526 // Sometimes we'll want to kill the channel (and notify all the endpoints that |
| 509 // their remotes are dead. | 527 // their remotes are dead. |
| 510 LOG(WARNING) << error_message; | 528 LOG(WARNING) << error_message; |
| 511 } | 529 } |
| 512 | 530 |
| 513 } // namespace system | 531 } // namespace system |
| 514 } // namespace mojo | 532 } // namespace mojo |
| OLD | NEW |