summaryrefslogtreecommitdiffstats
path: root/ipc/attachment_broker_privileged.cc
blob: 9f41892f721bedd73d6f9a3ac190e7215a6f422d (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// 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_privileged.h"

#include <algorithm>

#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "build/build_config.h"
#include "ipc/ipc_endpoint.h"

#if defined(OS_WIN)
#include "ipc/attachment_broker_privileged_win.h"
#endif

#if defined(OS_MACOSX) && !defined(OS_IOS)
#include <mach/mach.h>

#include "base/process/port_provider_mac.h"
#include "ipc/attachment_broker_privileged_mac.h"
#endif

namespace IPC {

namespace {

#if defined(OS_MACOSX) && !defined(OS_IOS)

// A fake port provider that does nothing. Intended for single process unit
// tests.
class FakePortProvider : public base::PortProvider {
  mach_port_t TaskForPid(base::ProcessHandle process) const override {
    DCHECK_EQ(process, getpid());
    return mach_task_self();
  }
};

base::LazyInstance<FakePortProvider>::Leaky
    g_fake_port_provider = LAZY_INSTANCE_INITIALIZER;

// Passed as a constructor parameter to AttachmentBrokerPrivilegedMac.
base::PortProvider* g_port_provider = nullptr;
#endif  // defined(OS_MACOSX) && !defined(OS_IOS)

// On platforms that support attachment brokering, returns a new instance of
// a platform-specific attachment broker. Otherwise returns |nullptr|.
// The caller takes ownership of the newly created instance, and is
// responsible for ensuring that the attachment broker lives longer than
// every IPC::Channel. The new instance automatically registers itself as the
// global attachment broker.
scoped_ptr<AttachmentBrokerPrivileged> CreateBroker() {
#if defined(OS_WIN)
  return scoped_ptr<AttachmentBrokerPrivileged>(
      new IPC::AttachmentBrokerPrivilegedWin);
#elif defined(OS_MACOSX) && !defined(OS_IOS)
  return scoped_ptr<AttachmentBrokerPrivileged>(
      new IPC::AttachmentBrokerPrivilegedMac(g_port_provider));
#else
  return nullptr;
#endif
}

// This class is wrapped in a LazyInstance to ensure that its constructor is
// only called once. The constructor creates an attachment broker and sets it as
// the global broker.
class AttachmentBrokerMakeOnce {
 public:
  AttachmentBrokerMakeOnce() : attachment_broker_(CreateBroker()) {}

 private:
  scoped_ptr<IPC::AttachmentBrokerPrivileged> attachment_broker_;
};

base::LazyInstance<AttachmentBrokerMakeOnce>::Leaky
    g_attachment_broker_make_once = LAZY_INSTANCE_INITIALIZER;

}  // namespace

AttachmentBrokerPrivileged::AttachmentBrokerPrivileged() {
  IPC::AttachmentBroker::SetGlobal(this);
}

AttachmentBrokerPrivileged::~AttachmentBrokerPrivileged() {
  IPC::AttachmentBroker::SetGlobal(nullptr);
}

#if defined(OS_MACOSX) && !defined(OS_IOS)
// static
void AttachmentBrokerPrivileged::CreateBrokerIfNeeded(
    base::PortProvider* provider) {
  g_port_provider = provider;
  g_attachment_broker_make_once.Get();
}
#else
// static
void AttachmentBrokerPrivileged::CreateBrokerIfNeeded() {
  g_attachment_broker_make_once.Get();
}
#endif  // defined(OS_MACOSX) && !defined(OS_IOS)

// static
void AttachmentBrokerPrivileged::CreateBrokerForSingleProcessTests() {
#if defined(OS_MACOSX) && !defined(OS_IOS)
  CreateBrokerIfNeeded(&g_fake_port_provider.Get());
#else
  CreateBrokerIfNeeded();
#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
}

void AttachmentBrokerPrivileged::RegisterCommunicationChannel(
    Endpoint* endpoint,
    scoped_refptr<base::SingleThreadTaskRunner> runner) {
  base::AutoLock auto_lock(*get_lock());
  endpoint->SetAttachmentBrokerEndpoint(true);
  auto it = std::find_if(endpoints_.begin(), endpoints_.end(),
                         [endpoint](const EndpointRunnerPair& pair) {
                           return pair.first == endpoint;
                         });
  DCHECK(endpoints_.end() == it);
  endpoints_.push_back(std::make_pair(endpoint, runner));
}

void AttachmentBrokerPrivileged::DeregisterCommunicationChannel(
    Endpoint* endpoint) {
  base::AutoLock auto_lock(*get_lock());
  auto it = std::find_if(endpoints_.begin(), endpoints_.end(),
                         [endpoint](const EndpointRunnerPair& pair) {
                           return pair.first == endpoint;
                         });
  if (it != endpoints_.end())
    endpoints_.erase(it);
}

bool AttachmentBrokerPrivileged::IsPrivilegedBroker() {
  return true;
}

AttachmentBrokerPrivileged::EndpointRunnerPair
AttachmentBrokerPrivileged::GetSenderWithProcessId(base::ProcessId id) {
  get_lock()->AssertAcquired();
  auto it = std::find_if(endpoints_.begin(), endpoints_.end(),
                         [id](const EndpointRunnerPair& pair) {
                           return pair.first->GetPeerPID() == id;
                         });
  if (it == endpoints_.end())
    return std::make_pair(nullptr, nullptr);
  return *it;
}

void AttachmentBrokerPrivileged::SendMessageToEndpoint(EndpointRunnerPair pair,
                                                       Message* message) {
  if (!pair.second || pair.second->BelongsToCurrentThread()) {
    pair.first->Send(message);
  } else {
    pair.second->PostTask(
        FROM_HERE,
        base::Bind(&AttachmentBrokerPrivileged::SendMessageToEndpoint,
                   base::Unretained(this), pair, message));
  }
}

void AttachmentBrokerPrivileged::LogError(UMAError error) {
  UMA_HISTOGRAM_ENUMERATION(
      "IPC.AttachmentBrokerPrivileged.BrokerAttachmentError", error, ERROR_MAX);
}

}  // namespace IPC