• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ipc/mojo/ipc_mojo_bootstrap.h"
6 
7 #include "base/logging.h"
8 #include "base/process/process_handle.h"
9 #include "ipc/ipc_message_utils.h"
10 #include "ipc/ipc_platform_file.h"
11 #include "mojo/embedder/platform_channel_pair.h"
12 
13 namespace IPC {
14 
15 namespace {
16 
17 // MojoBootstrap for the server process. You should create the instance
18 // using MojoBootstrap::Create().
19 class IPC_MOJO_EXPORT MojoServerBootstrap : public MojoBootstrap {
20  public:
21   MojoServerBootstrap();
22 
23   virtual void OnClientLaunched(base::ProcessHandle process) OVERRIDE;
24 
25  private:
26   void SendClientPipe();
27   void SendClientPipeIfReady();
28 
29   // Listener implementations
30   virtual bool OnMessageReceived(const Message& message) OVERRIDE;
31   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
32 
33   mojo::embedder::ScopedPlatformHandle server_pipe_;
34   base::ProcessHandle client_process_;
35   bool connected_;
36 
37   DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap);
38 };
39 
MojoServerBootstrap()40 MojoServerBootstrap::MojoServerBootstrap()
41     : client_process_(base::kNullProcessHandle), connected_(false) {
42 }
43 
SendClientPipe()44 void MojoServerBootstrap::SendClientPipe() {
45   DCHECK_EQ(state(), STATE_INITIALIZED);
46   DCHECK_NE(client_process_, base::kNullProcessHandle);
47   DCHECK(connected_);
48 
49   mojo::embedder::PlatformChannelPair channel_pair;
50   server_pipe_ = channel_pair.PassServerHandle();
51   PlatformFileForTransit client_pipe = GetFileHandleForProcess(
52 #if defined(OS_POSIX)
53       channel_pair.PassClientHandle().release().fd,
54 #else
55       channel_pair.PassClientHandle().release().handle,
56 #endif
57       client_process_,
58       true);
59   CHECK(client_pipe != IPC::InvalidPlatformFileForTransit());
60   scoped_ptr<Message> message(new Message());
61   ParamTraits<PlatformFileForTransit>::Write(message.get(), client_pipe);
62   Send(message.release());
63 
64   set_state(STATE_WAITING_ACK);
65 }
66 
SendClientPipeIfReady()67 void MojoServerBootstrap::SendClientPipeIfReady() {
68   // Is the client launched?
69   if (client_process_ == base::kNullProcessHandle)
70     return;
71   // Has the bootstrap channel been made?
72   if (!connected_)
73     return;
74   SendClientPipe();
75 }
76 
OnClientLaunched(base::ProcessHandle process)77 void MojoServerBootstrap::OnClientLaunched(base::ProcessHandle process) {
78   DCHECK_EQ(state(), STATE_INITIALIZED);
79   DCHECK_NE(process, base::kNullProcessHandle);
80   client_process_ = process;
81   SendClientPipeIfReady();
82 }
83 
OnChannelConnected(int32 peer_pid)84 void MojoServerBootstrap::OnChannelConnected(int32 peer_pid) {
85   DCHECK_EQ(state(), STATE_INITIALIZED);
86   connected_ = true;
87   SendClientPipeIfReady();
88 }
89 
OnMessageReceived(const Message &)90 bool MojoServerBootstrap::OnMessageReceived(const Message&) {
91   DCHECK_EQ(state(), STATE_WAITING_ACK);
92   set_state(STATE_READY);
93 
94   delegate()->OnPipeAvailable(
95       mojo::embedder::ScopedPlatformHandle(server_pipe_.release()));
96 
97   return true;
98 }
99 
100 // MojoBootstrap for client processes. You should create the instance
101 // using MojoBootstrap::Create().
102 class IPC_MOJO_EXPORT MojoClientBootstrap : public MojoBootstrap {
103  public:
104   MojoClientBootstrap();
105 
106   virtual void OnClientLaunched(base::ProcessHandle process) OVERRIDE;
107 
108  private:
109   // Listener implementations
110   virtual bool OnMessageReceived(const Message& message) OVERRIDE;
111   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
112 
113   DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap);
114 };
115 
MojoClientBootstrap()116 MojoClientBootstrap::MojoClientBootstrap() {
117 }
118 
OnMessageReceived(const Message & message)119 bool MojoClientBootstrap::OnMessageReceived(const Message& message) {
120   PlatformFileForTransit pipe;
121   PickleIterator iter(message);
122   if (!ParamTraits<PlatformFileForTransit>::Read(&message, &iter, &pipe)) {
123     DLOG(WARNING) << "Failed to read a file handle from bootstrap channel.";
124     message.set_dispatch_error();
125     return false;
126   }
127 
128   // Sends ACK back.
129   Send(new Message());
130   set_state(STATE_READY);
131   delegate()->OnPipeAvailable(
132       mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle(
133           PlatformFileForTransitToPlatformFile(pipe))));
134 
135   return true;
136 }
137 
OnClientLaunched(base::ProcessHandle process)138 void MojoClientBootstrap::OnClientLaunched(base::ProcessHandle process) {
139   // This notification should happen only on server processes.
140   NOTREACHED();
141 }
142 
OnChannelConnected(int32 peer_pid)143 void MojoClientBootstrap::OnChannelConnected(int32 peer_pid) {
144 }
145 
146 }  // namespace
147 
148 // MojoBootstrap
149 
150 // static
Create(ChannelHandle handle,Channel::Mode mode,Delegate * delegate)151 scoped_ptr<MojoBootstrap> MojoBootstrap::Create(ChannelHandle handle,
152                                                 Channel::Mode mode,
153                                                 Delegate* delegate) {
154   CHECK(mode == Channel::MODE_CLIENT || mode == Channel::MODE_SERVER);
155   scoped_ptr<MojoBootstrap> self =
156       mode == Channel::MODE_CLIENT
157           ? scoped_ptr<MojoBootstrap>(new MojoClientBootstrap())
158           : scoped_ptr<MojoBootstrap>(new MojoServerBootstrap());
159   scoped_ptr<Channel> bootstrap_channel =
160       Channel::Create(handle, mode, self.get());
161   self->Init(bootstrap_channel.Pass(), delegate);
162   return self.Pass();
163 }
164 
MojoBootstrap()165 MojoBootstrap::MojoBootstrap() : delegate_(NULL), state_(STATE_INITIALIZED) {
166 }
167 
~MojoBootstrap()168 MojoBootstrap::~MojoBootstrap() {
169 }
170 
Init(scoped_ptr<Channel> channel,Delegate * delegate)171 void MojoBootstrap::Init(scoped_ptr<Channel> channel, Delegate* delegate) {
172   channel_ = channel.Pass();
173   delegate_ = delegate;
174 }
175 
Connect()176 bool MojoBootstrap::Connect() {
177   return channel_->Connect();
178 }
179 
OnBadMessageReceived(const Message & message)180 void MojoBootstrap::OnBadMessageReceived(const Message& message) {
181   delegate_->OnBootstrapError();
182 }
183 
OnChannelError()184 void MojoBootstrap::OnChannelError() {
185   if (state_ == STATE_READY)
186     return;
187   DLOG(WARNING) << "Detected error on Mojo bootstrap channel.";
188   delegate()->OnBootstrapError();
189 }
190 
Send(Message * message)191 bool MojoBootstrap::Send(Message* message) {
192   return channel_->Send(message);
193 }
194 
195 #if defined(OS_POSIX) && !defined(OS_NACL)
GetClientFileDescriptor() const196 int MojoBootstrap::GetClientFileDescriptor() const {
197   return channel_->GetClientFileDescriptor();
198 }
199 
TakeClientFileDescriptor()200 int MojoBootstrap::TakeClientFileDescriptor() {
201   return channel_->TakeClientFileDescriptor();
202 }
203 #endif  // defined(OS_POSIX) && !defined(OS_NACL)
204 
205 }  // namespace IPC
206