| // Copyright 2015 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 "ipc/attachment_broker.h" |
| |
| #include <algorithm> |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/sequenced_task_runner.h" |
| |
| namespace { |
| IPC::AttachmentBroker* g_attachment_broker = nullptr; |
| } |
| |
| namespace IPC { |
| |
| // static |
| void AttachmentBroker::SetGlobal(AttachmentBroker* broker) { |
| CHECK(!g_attachment_broker || !broker) |
| << "Global attachment broker address: " << broker |
| << ". New attachment broker address: " << broker; |
| g_attachment_broker = broker; |
| } |
| |
| // static |
| AttachmentBroker* AttachmentBroker::GetGlobal() { |
| return g_attachment_broker; |
| } |
| |
| AttachmentBroker::AttachmentBroker() : last_unique_id_(0) {} |
| AttachmentBroker::~AttachmentBroker() {} |
| |
| bool AttachmentBroker::GetAttachmentWithId( |
| BrokerableAttachment::AttachmentId id, |
| scoped_refptr<BrokerableAttachment>* out_attachment) { |
| base::AutoLock auto_lock(*get_lock()); |
| for (AttachmentVector::iterator it = attachments_.begin(); |
| it != attachments_.end(); ++it) { |
| if ((*it)->GetIdentifier() == id) { |
| *out_attachment = *it; |
| attachments_.erase(it); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void AttachmentBroker::AddObserver( |
| AttachmentBroker::Observer* observer, |
| const scoped_refptr<base::SequencedTaskRunner>& runner) { |
| base::AutoLock auto_lock(*get_lock()); |
| auto it = std::find_if(observers_.begin(), observers_.end(), |
| [observer](const ObserverInfo& info) { |
| return info.observer == observer; |
| }); |
| if (it == observers_.end()) { |
| ObserverInfo info; |
| info.observer = observer; |
| info.runner = runner; |
| info.unique_id = ++last_unique_id_; |
| observers_.push_back(info); |
| } |
| } |
| |
| void AttachmentBroker::RemoveObserver(AttachmentBroker::Observer* observer) { |
| base::AutoLock auto_lock(*get_lock()); |
| auto it = std::find_if(observers_.begin(), observers_.end(), |
| [observer](const ObserverInfo& info) { |
| return info.observer == observer; |
| }); |
| if (it != observers_.end()) |
| observers_.erase(it); |
| } |
| |
| void AttachmentBroker::RegisterCommunicationChannel(Endpoint* endpoint) { |
| NOTREACHED(); |
| } |
| |
| void AttachmentBroker::DeregisterCommunicationChannel(Endpoint* endpoint) { |
| NOTREACHED(); |
| } |
| |
| void AttachmentBroker::HandleReceivedAttachment( |
| const scoped_refptr<BrokerableAttachment>& attachment) { |
| { |
| base::AutoLock auto_lock(*get_lock()); |
| attachments_.push_back(attachment); |
| } |
| NotifyObservers(attachment->GetIdentifier()); |
| } |
| |
| void AttachmentBroker::NotifyObservers( |
| const BrokerableAttachment::AttachmentId& id) { |
| base::AutoLock auto_lock(*get_lock()); |
| |
| // Dispatch notifications onto the appropriate task runners. This has two |
| // effects: |
| // 1. Ensures that the notification is posted from the right task runner. |
| // 2. Avoids any complications from re-entrant functions, since one of the |
| // observers may be halfway through processing some messages. |
| for (const auto& info : observers_) { |
| info.runner->PostTask( |
| FROM_HERE, base::Bind(&AttachmentBroker::NotifyObserver, |
| base::Unretained(this), info.unique_id, id)); |
| } |
| } |
| |
| void AttachmentBroker::NotifyObserver( |
| int unique_id, |
| const BrokerableAttachment::AttachmentId& id) { |
| Observer* observer = nullptr; |
| { |
| // Check that the same observer is still registered. |
| base::AutoLock auto_lock(*get_lock()); |
| auto it = std::find_if(observers_.begin(), observers_.end(), |
| [unique_id](const ObserverInfo& info) { |
| return info.unique_id == unique_id; |
| }); |
| if (it == observers_.end()) |
| return; |
| observer = it->observer; |
| } |
| |
| observer->ReceivedBrokerableAttachmentWithId(id); |
| } |
| |
| AttachmentBroker::ObserverInfo::ObserverInfo() {} |
| AttachmentBroker::ObserverInfo::~ObserverInfo() {} |
| |
| } // namespace IPC |