1// Copyright (c) 2012 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 "chrome/browser/extensions/api/messaging/message_service.h"
6
7#include "base/atomic_sequence_num.h"
8#include "base/bind.h"
9#include "base/callback.h"
10#include "base/json/json_writer.h"
11#include "base/lazy_instance.h"
12#include "base/metrics/histogram.h"
13#include "base/stl_util.h"
14#include "base/values.h"
15#include "chrome/browser/chrome_notification_types.h"
16#include "chrome/browser/extensions/api/messaging/extension_message_port.h"
17#include "chrome/browser/extensions/api/messaging/native_message_port.h"
18#include "chrome/browser/extensions/extension_host.h"
19#include "chrome/browser/extensions/extension_process_manager.h"
20#include "chrome/browser/extensions/extension_service.h"
21#include "chrome/browser/extensions/extension_system.h"
22#include "chrome/browser/extensions/extension_tab_util.h"
23#include "chrome/browser/extensions/lazy_background_task_queue.h"
24#include "chrome/browser/extensions/process_map.h"
25#include "chrome/browser/profiles/profile.h"
26#include "chrome/browser/tab_contents/tab_util.h"
27#include "chrome/common/extensions/background_info.h"
28#include "chrome/common/extensions/extension.h"
29#include "chrome/common/extensions/extension_manifest_constants.h"
30#include "chrome/common/extensions/extension_messages.h"
31#include "chrome/common/extensions/incognito_handler.h"
32#include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
33#include "content/public/browser/browser_thread.h"
34#include "content/public/browser/notification_service.h"
35#include "content/public/browser/render_process_host.h"
36#include "content/public/browser/render_view_host.h"
37#include "content/public/browser/render_widget_host.h"
38#include "content/public/browser/render_widget_host_view.h"
39#include "content/public/browser/site_instance.h"
40#include "content/public/browser/web_contents.h"
41#include "url/gurl.h"
42
43using content::SiteInstance;
44using content::WebContents;
45
46// Since we have 2 ports for every channel, we just index channels by half the
47// port ID.
48#define GET_CHANNEL_ID(port_id) ((port_id) / 2)
49#define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
50#define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
51
52// Port1 is always even, port2 is always odd.
53#define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
54
55// Change even to odd and vice versa, to get the other side of a given channel.
56#define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
57
58namespace extensions {
59
60namespace {
61const char kReceivingEndDoesntExistError[] =
62    "Could not establish connection. Receiving end does not exist.";
63const char kMissingPermissionError[] =
64    "Access to native messaging requires nativeMessaging permission.";
65const char kNativeMessagingNotSupportedError[] =
66    "Native Messaging is not supported on this platform.";
67}
68
69struct MessageService::MessageChannel {
70  scoped_ptr<MessagePort> opener;
71  scoped_ptr<MessagePort> receiver;
72};
73
74struct MessageService::OpenChannelParams {
75  content::RenderProcessHost* source;
76  base::DictionaryValue source_tab;
77  scoped_ptr<MessagePort> receiver;
78  int receiver_port_id;
79  std::string source_extension_id;
80  std::string target_extension_id;
81  GURL source_url;
82  std::string channel_name;
83
84  // Takes ownership of receiver.
85  OpenChannelParams(content::RenderProcessHost* source,
86                    scoped_ptr<base::DictionaryValue> source_tab,
87                    MessagePort* receiver,
88                    int receiver_port_id,
89                    const std::string& source_extension_id,
90                    const std::string& target_extension_id,
91                    const GURL& source_url,
92                    const std::string& channel_name)
93      : source(source),
94        receiver(receiver),
95        receiver_port_id(receiver_port_id),
96        source_extension_id(source_extension_id),
97        target_extension_id(target_extension_id),
98        source_url(source_url),
99        channel_name(channel_name) {
100    if (source_tab)
101      this->source_tab.Swap(source_tab.get());
102  }
103
104 private:
105  DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
106};
107
108namespace {
109
110static base::StaticAtomicSequenceNumber g_next_channel_id;
111static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
112
113static content::RenderProcessHost* GetExtensionProcess(
114    Profile* profile, const std::string& extension_id) {
115  SiteInstance* site_instance =
116      extensions::ExtensionSystem::Get(profile)->process_manager()->
117          GetSiteInstanceForURL(
118              Extension::GetBaseURLFromExtensionId(extension_id));
119
120  if (!site_instance->HasProcess())
121    return NULL;
122
123  return site_instance->GetProcess();
124}
125
126}  // namespace
127
128content::RenderProcessHost*
129    MessageService::MessagePort::GetRenderProcessHost() {
130  return NULL;
131}
132
133// static
134void MessageService::AllocatePortIdPair(int* port1, int* port2) {
135  unsigned channel_id =
136      static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
137
138  if (channel_id == 0) {
139    int overflow_count = g_channel_id_overflow_count.GetNext();
140    if (overflow_count > 0)
141      UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
142  }
143
144  unsigned port1_id = channel_id * 2;
145  unsigned port2_id = channel_id * 2 + 1;
146
147  // Sanity checks to make sure our channel<->port converters are correct.
148  DCHECK(IS_OPENER_PORT_ID(port1_id));
149  DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
150  DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
151  DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
152  DCHECK(GET_CHANNEL_ID(port1_id) == channel_id);
153  DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id);
154  DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id);
155
156  *port1 = port1_id;
157  *port2 = port2_id;
158}
159
160MessageService::MessageService(Profile* profile)
161    : lazy_background_task_queue_(
162          ExtensionSystem::Get(profile)->lazy_background_task_queue()),
163      weak_factory_(this) {
164  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
165                 content::NotificationService::AllBrowserContextsAndSources());
166  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
167                 content::NotificationService::AllBrowserContextsAndSources());
168}
169
170MessageService::~MessageService() {
171  STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
172  channels_.clear();
173}
174
175static base::LazyInstance<ProfileKeyedAPIFactory<MessageService> >
176g_factory = LAZY_INSTANCE_INITIALIZER;
177
178// static
179ProfileKeyedAPIFactory<MessageService>* MessageService::GetFactoryInstance() {
180  return &g_factory.Get();
181}
182
183// static
184MessageService* MessageService::Get(Profile* profile) {
185  return ProfileKeyedAPIFactory<MessageService>::GetForProfile(profile);
186}
187
188void MessageService::OpenChannelToExtension(
189    int source_process_id, int source_routing_id, int receiver_port_id,
190    const std::string& source_extension_id,
191    const std::string& target_extension_id,
192    const GURL& source_url,
193    const std::string& channel_name) {
194  content::RenderProcessHost* source =
195      content::RenderProcessHost::FromID(source_process_id);
196  if (!source)
197    return;
198  Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
199
200  const Extension* target_extension = ExtensionSystem::Get(profile)->
201      extension_service()->extensions()->GetByID(target_extension_id);
202  if (!target_extension) {
203    DispatchOnDisconnect(
204        source, receiver_port_id, kReceivingEndDoesntExistError);
205    return;
206  }
207
208  ExtensionService* extension_service =
209      extensions::ExtensionSystem::Get(profile)->extension_service();
210
211  if (profile->IsOffTheRecord() &&
212      !extension_service->IsIncognitoEnabled(target_extension_id)) {
213    DispatchOnDisconnect(
214        source, receiver_port_id, kReceivingEndDoesntExistError);
215    return;
216  }
217
218  if (source_extension_id != target_extension_id) {
219    // It's an external connection. Check the externally_connectable manifest
220    // key if it's present. If it's not, we allow connection from any extension
221    // but not webpages.
222    ExternallyConnectableInfo* externally_connectable =
223        static_cast<ExternallyConnectableInfo*>(
224            target_extension->GetManifestData(
225                extension_manifest_keys::kExternallyConnectable));
226    bool is_externally_connectable = false;
227
228    if (externally_connectable) {
229      if (source_extension_id.empty()) {
230        // No source extension ID so the source was a web page. Check that the
231        // URL matches.
232        is_externally_connectable =
233            externally_connectable->matches.MatchesURL(source_url);
234      } else {
235        // Source extension ID so the source was an extension. Check that the
236        // extension matches.
237        is_externally_connectable =
238            externally_connectable->IdCanConnect(source_extension_id);
239      }
240    } else {
241      // Default behaviour. Any extension, no webpages.
242      is_externally_connectable = !source_extension_id.empty();
243    }
244
245    if (!is_externally_connectable) {
246      // Important: use kReceivingEndDoesntExistError here so that we don't
247      // leak information about this extension to callers. This way it's
248      // indistinguishable from the extension just not existing.
249      DispatchOnDisconnect(
250          source, receiver_port_id, kReceivingEndDoesntExistError);
251      return;
252    }
253  }
254
255  // Note: we use the source's profile here. If the source is an incognito
256  // process, we will use the incognito EPM to find the right extension process,
257  // which depends on whether the extension uses spanning or split mode.
258  MessagePort* receiver = new ExtensionMessagePort(
259      GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL,
260      target_extension_id);
261  WebContents* source_contents = tab_util::GetWebContentsByID(
262      source_process_id, source_routing_id);
263
264  // Include info about the opener's tab (if it was a tab).
265  scoped_ptr<base::DictionaryValue> source_tab;
266  GURL source_url_for_tab;
267
268  if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
269    // Platform apps can be sent messages, but don't have a Tab concept.
270    if (!target_extension->is_platform_app())
271      source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
272    source_url_for_tab = source_url;
273  }
274
275  OpenChannelParams* params = new OpenChannelParams(source,
276                                                    source_tab.Pass(),
277                                                    receiver,
278                                                    receiver_port_id,
279                                                    source_extension_id,
280                                                    target_extension_id,
281                                                    source_url_for_tab,
282                                                    channel_name);
283
284  // The target might be a lazy background page. In that case, we have to check
285  // if it is loaded and ready, and if not, queue up the task and load the
286  // page.
287  if (MaybeAddPendingOpenChannelTask(profile, target_extension, params)) {
288    return;
289  }
290
291  OpenChannelImpl(make_scoped_ptr(params));
292}
293
294void MessageService::OpenChannelToNativeApp(
295    int source_process_id,
296    int source_routing_id,
297    int receiver_port_id,
298    const std::string& source_extension_id,
299    const std::string& native_app_name) {
300  content::RenderProcessHost* source =
301      content::RenderProcessHost::FromID(source_process_id);
302  if (!source)
303    return;
304
305#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
306  Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
307  ExtensionService* extension_service =
308      extensions::ExtensionSystem::Get(profile)->extension_service();
309  bool has_permission = false;
310  if (extension_service) {
311    const Extension* extension =
312        extension_service->GetExtensionById(source_extension_id, false);
313    has_permission = extension && extension->HasAPIPermission(
314        APIPermission::kNativeMessaging);
315  }
316
317  if (!has_permission) {
318    DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
319    return;
320  }
321
322  scoped_ptr<MessageChannel> channel(new MessageChannel());
323  channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
324                                                 source_extension_id));
325
326  // Get handle of the native view and pass it to the native messaging host.
327  gfx::NativeView native_view =
328      content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
329          GetView()->GetNativeView();
330
331  scoped_ptr<NativeMessageProcessHost> native_process =
332      NativeMessageProcessHost::Create(
333          native_view,
334          base::WeakPtr<NativeMessageProcessHost::Client>(
335              weak_factory_.GetWeakPtr()),
336          source_extension_id, native_app_name, receiver_port_id);
337
338  // Abandon the channel.
339  if (!native_process.get()) {
340    LOG(ERROR) << "Failed to create native process.";
341    DispatchOnDisconnect(
342        source, receiver_port_id, kReceivingEndDoesntExistError);
343    return;
344  }
345  channel->receiver.reset(new NativeMessagePort(native_process.release()));
346
347  // Keep the opener alive until the channel is closed.
348  channel->opener->IncrementLazyKeepaliveCount();
349
350  AddChannel(channel.release(), receiver_port_id);
351#else  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
352  DispatchOnDisconnect(
353      source, receiver_port_id, kNativeMessagingNotSupportedError);
354#endif  // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
355}
356
357void MessageService::OpenChannelToTab(
358    int source_process_id, int source_routing_id, int receiver_port_id,
359    int tab_id, const std::string& extension_id,
360    const std::string& channel_name) {
361  content::RenderProcessHost* source =
362      content::RenderProcessHost::FromID(source_process_id);
363  if (!source)
364    return;
365  Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
366
367  WebContents* contents = NULL;
368  scoped_ptr<MessagePort> receiver;
369  if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
370                                   NULL, NULL, &contents, NULL)) {
371    receiver.reset(new ExtensionMessagePort(
372        contents->GetRenderProcessHost(),
373        contents->GetRenderViewHost()->GetRoutingID(),
374        extension_id));
375  }
376
377  if (contents && contents->GetController().NeedsReload()) {
378    // The tab isn't loaded yet. Don't attempt to connect.
379    DispatchOnDisconnect(
380        source, receiver_port_id, kReceivingEndDoesntExistError);
381    return;
382  }
383
384  scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
385        source,
386        scoped_ptr<base::DictionaryValue>(),  // Source tab doesn't make sense
387                                              // for opening to tabs.
388        receiver.release(),
389        receiver_port_id,
390        extension_id,
391        extension_id,
392        GURL(),  // Source URL doesn't make sense for opening to tabs.
393        channel_name));
394  OpenChannelImpl(params.Pass());
395}
396
397bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
398  if (!params->source)
399    return false;  // Closed while in flight.
400
401  if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
402    DispatchOnDisconnect(params->source,
403                         params->receiver_port_id,
404                         kReceivingEndDoesntExistError);
405    return false;
406  }
407
408  // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
409  // http://code.google.com/p/chromium/issues/detail?id=19067
410  CHECK(params->receiver->GetRenderProcessHost());
411
412  MessageChannel* channel(new MessageChannel);
413  channel->opener.reset(new ExtensionMessagePort(params->source,
414                                                 MSG_ROUTING_CONTROL,
415                                                 params->source_extension_id));
416  channel->receiver.reset(params->receiver.release());
417
418  CHECK(channel->receiver->GetRenderProcessHost());
419
420  AddChannel(channel, params->receiver_port_id);
421
422  CHECK(channel->receiver->GetRenderProcessHost());
423
424  // Send the connect event to the receiver.  Give it the opener's port ID (the
425  // opener has the opposite port ID).
426  channel->receiver->DispatchOnConnect(params->receiver_port_id,
427                                       params->channel_name,
428                                       params->source_tab,
429                                       params->source_extension_id,
430                                       params->target_extension_id,
431                                       params->source_url);
432
433  // Keep both ends of the channel alive until the channel is closed.
434  channel->opener->IncrementLazyKeepaliveCount();
435  channel->receiver->IncrementLazyKeepaliveCount();
436  return true;
437}
438
439void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
440  int channel_id = GET_CHANNEL_ID(receiver_port_id);
441  CHECK(channels_.find(channel_id) == channels_.end());
442  channels_[channel_id] = channel;
443  pending_channels_.erase(channel_id);
444}
445
446void MessageService::CloseChannel(int port_id,
447                                  const std::string& error_message) {
448  // Note: The channel might be gone already, if the other side closed first.
449  int channel_id = GET_CHANNEL_ID(port_id);
450  MessageChannelMap::iterator it = channels_.find(channel_id);
451  if (it == channels_.end()) {
452    PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
453    if (pending != pending_channels_.end()) {
454      lazy_background_task_queue_->AddPendingTask(
455          pending->second.first, pending->second.second,
456          base::Bind(&MessageService::PendingCloseChannel,
457                     weak_factory_.GetWeakPtr(), port_id, error_message));
458    }
459    return;
460  }
461  CloseChannelImpl(it, port_id, error_message, true);
462}
463
464void MessageService::CloseChannelImpl(
465    MessageChannelMap::iterator channel_iter,
466    int closing_port_id,
467    const std::string& error_message,
468    bool notify_other_port) {
469  MessageChannel* channel = channel_iter->second;
470
471  // Notify the other side.
472  if (notify_other_port) {
473    MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
474        channel->receiver.get() : channel->opener.get();
475    port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
476                               error_message);
477  }
478
479  // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
480  channel->opener->DecrementLazyKeepaliveCount();
481  channel->receiver->DecrementLazyKeepaliveCount();
482
483  delete channel_iter->second;
484  channels_.erase(channel_iter);
485}
486
487void MessageService::PostMessage(
488    int source_port_id, const std::string& message) {
489  int channel_id = GET_CHANNEL_ID(source_port_id);
490  MessageChannelMap::iterator iter = channels_.find(channel_id);
491  if (iter == channels_.end()) {
492    // If this channel is pending, queue up the PostMessage to run once
493    // the channel opens.
494    PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
495    if (pending != pending_channels_.end()) {
496      lazy_background_task_queue_->AddPendingTask(
497          pending->second.first, pending->second.second,
498          base::Bind(&MessageService::PendingPostMessage,
499                     weak_factory_.GetWeakPtr(), source_port_id, message));
500    }
501    return;
502  }
503
504  // Figure out which port the ID corresponds to.
505  int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
506  MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
507      iter->second->opener.get() : iter->second->receiver.get();
508
509  port->DispatchOnMessage(message, dest_port_id);
510}
511
512void MessageService::PostMessageFromNativeProcess(int port_id,
513                                                  const std::string& message) {
514  PostMessage(port_id, message);
515}
516
517void MessageService::Observe(int type,
518                             const content::NotificationSource& source,
519                             const content::NotificationDetails& details) {
520  switch (type) {
521    case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
522    case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
523      content::RenderProcessHost* renderer =
524          content::Source<content::RenderProcessHost>(source).ptr();
525      OnProcessClosed(renderer);
526      break;
527    }
528    default:
529      NOTREACHED();
530      return;
531  }
532}
533
534void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
535  // Close any channels that share this renderer.  We notify the opposite
536  // port that his pair has closed.
537  for (MessageChannelMap::iterator it = channels_.begin();
538       it != channels_.end(); ) {
539    MessageChannelMap::iterator current = it++;
540
541    content::RenderProcessHost* opener_process =
542        current->second->opener->GetRenderProcessHost();
543    content::RenderProcessHost* receiver_process =
544        current->second->receiver->GetRenderProcessHost();
545
546    // Only notify the other side if it has a different porocess host.
547    bool notify_other_port = opener_process && receiver_process &&
548        opener_process != receiver_process;
549
550    if (opener_process == process) {
551      CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
552                       std::string(), notify_other_port);
553    } else if (receiver_process == process) {
554      CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
555                       std::string(), notify_other_port);
556    }
557  }
558}
559
560bool MessageService::MaybeAddPendingOpenChannelTask(
561    Profile* profile,
562    const Extension* extension,
563    OpenChannelParams* params) {
564  if (!BackgroundInfo::HasLazyBackgroundPage(extension))
565    return false;
566
567  // If the extension uses spanning incognito mode, make sure we're always
568  // using the original profile since that is what the extension process
569  // will use.
570  if (!IncognitoInfo::IsSplitMode(extension))
571    profile = profile->GetOriginalProfile();
572
573  if (!lazy_background_task_queue_->ShouldEnqueueTask(profile, extension))
574    return false;
575
576  pending_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
577      PendingChannel(profile, extension->id());
578  scoped_ptr<OpenChannelParams> scoped_params(params);
579  lazy_background_task_queue_->AddPendingTask(profile, extension->id(),
580      base::Bind(&MessageService::PendingOpenChannel,
581                 weak_factory_.GetWeakPtr(), base::Passed(&scoped_params),
582                 params->source->GetID()));
583  return true;
584}
585
586void MessageService::PendingOpenChannel(scoped_ptr<OpenChannelParams> params,
587                                        int source_process_id,
588                                        ExtensionHost* host) {
589  if (!host)
590    return;  // TODO(mpcomplete): notify source of disconnect?
591
592  // Re-lookup the source process since it may no longer be valid.
593  content::RenderProcessHost* source =
594      content::RenderProcessHost::FromID(source_process_id);
595  if (!source)
596    return;
597
598  params->source = source;
599  params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
600                                                  MSG_ROUTING_CONTROL,
601                                                  params->target_extension_id));
602  OpenChannelImpl(params.Pass());
603}
604
605void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
606                                          int port_id,
607                                          const std::string& error_message) {
608  ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
609  port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
610}
611
612}  // namespace extensions
613