summaryrefslogtreecommitdiffstats
path: root/ipc/attachment_broker.cc
blob: f53a4cf0123856fee418bf77a1e7a05e3bc9eb2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// 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) {
  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);

    // Give the observer a chance to handle attachments that arrived while the
    // observer was handling the message that caused it to register, but our
    // mutex was not yet locked.
    for (const auto& attachment : attachments_) {
      info.runner->PostTask(
          FROM_HERE,
          base::Bind(&AttachmentBroker::NotifyObserver, base::Unretained(this),
                     info.unique_id, attachment->GetIdentifier()));
    }
  }
}

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,
    scoped_refptr<base::SingleThreadTaskRunner> runner) {
  NOTREACHED();
}

void AttachmentBroker::DeregisterCommunicationChannel(Endpoint* endpoint) {
  NOTREACHED();
}

void AttachmentBroker::RegisterBrokerCommunicationChannel(Endpoint* endpoint) {
  NOTREACHED();
}

void AttachmentBroker::DeregisterBrokerCommunicationChannel(
    Endpoint* endpoint) {
  NOTREACHED();
}

bool AttachmentBroker::IsPrivilegedBroker() {
  NOTREACHED();
  return false;
}

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(const ObserverInfo& other) =
    default;
AttachmentBroker::ObserverInfo::~ObserverInfo() {}

}  // namespace IPC