Home | History | Annotate | Download | only in nacl_irt
      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 "ppapi/nacl_irt/ppapi_dispatcher.h"
      6 
      7 #include <map>
      8 #include <set>
      9 
     10 #include "build/build_config.h"
     11 // Need to include this before most other files because it defines
     12 // IPC_MESSAGE_LOG_ENABLED. We need to use it to define
     13 // IPC_MESSAGE_MACROS_LOG_ENABLED so ppapi_messages.h will generate the
     14 // ViewMsgLog et al. functions.
     15 
     16 #include "base/command_line.h"
     17 #include "base/memory/ref_counted.h"
     18 #include "base/message_loop/message_loop.h"
     19 #include "base/synchronization/waitable_event.h"
     20 #include "components/tracing/child_trace_message_filter.h"
     21 #include "ipc/ipc_channel_handle.h"
     22 #include "ipc/ipc_logging.h"
     23 #include "ipc/ipc_message.h"
     24 #include "ppapi/c/ppp.h"
     25 #include "ppapi/c/ppp_instance.h"
     26 #include "ppapi/nacl_irt/manifest_service.h"
     27 #include "ppapi/nacl_irt/plugin_startup.h"
     28 #include "ppapi/proxy/plugin_dispatcher.h"
     29 #include "ppapi/proxy/plugin_globals.h"
     30 #include "ppapi/proxy/plugin_message_filter.h"
     31 #include "ppapi/proxy/plugin_proxy_delegate.h"
     32 #include "ppapi/proxy/resource_reply_thread_registrar.h"
     33 
     34 #if defined(IPC_MESSAGE_LOG_ENABLED)
     35 #include "base/containers/hash_tables.h"
     36 
     37 LogFunctionMap g_log_function_mapping;
     38 
     39 #define IPC_MESSAGE_MACROS_LOG_ENABLED
     40 #define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
     41   g_log_function_mapping[msg_id] = logger
     42 
     43 #endif
     44 #include "ppapi/proxy/ppapi_messages.h"
     45 
     46 namespace ppapi {
     47 
     48 PpapiDispatcher::PpapiDispatcher(scoped_refptr<base::MessageLoopProxy> io_loop,
     49                                  base::WaitableEvent* shutdown_event,
     50                                  int browser_ipc_fd,
     51                                  int renderer_ipc_fd)
     52     : next_plugin_dispatcher_id_(0),
     53       message_loop_(io_loop),
     54       shutdown_event_(shutdown_event),
     55       renderer_ipc_fd_(renderer_ipc_fd) {
     56 #if defined(IPC_MESSAGE_LOG_ENABLED)
     57   IPC::Logging::set_log_function_map(&g_log_function_mapping);
     58 #endif
     59 
     60   IPC::ChannelHandle channel_handle(
     61       "NaCl IPC", base::FileDescriptor(browser_ipc_fd, false));
     62 
     63   // Delay initializing the SyncChannel until after we add filters. This
     64   // ensures that the filters won't miss any messages received by
     65   // the channel.
     66   channel_ =
     67       IPC::SyncChannel::Create(this, GetIPCMessageLoop(), GetShutdownEvent());
     68   channel_->AddFilter(new proxy::PluginMessageFilter(
     69       NULL, proxy::PluginGlobals::Get()->resource_reply_thread_registrar()));
     70   channel_->AddFilter(
     71       new tracing::ChildTraceMessageFilter(message_loop_.get()));
     72   channel_->Init(channel_handle, IPC::Channel::MODE_SERVER, true);
     73 }
     74 
     75 base::MessageLoopProxy* PpapiDispatcher::GetIPCMessageLoop() {
     76   return message_loop_.get();
     77 }
     78 
     79 base::WaitableEvent* PpapiDispatcher::GetShutdownEvent() {
     80   return shutdown_event_;
     81 }
     82 
     83 IPC::PlatformFileForTransit PpapiDispatcher::ShareHandleWithRemote(
     84     base::PlatformFile handle,
     85     base::ProcessId peer_pid,
     86     bool should_close_source) {
     87   return IPC::InvalidPlatformFileForTransit();
     88 }
     89 
     90 std::set<PP_Instance>* PpapiDispatcher::GetGloballySeenInstanceIDSet() {
     91   return &instances_;
     92 }
     93 
     94 uint32 PpapiDispatcher::Register(proxy::PluginDispatcher* plugin_dispatcher) {
     95   if (!plugin_dispatcher ||
     96       plugin_dispatchers_.size() >= std::numeric_limits<uint32>::max()) {
     97     return 0;
     98   }
     99 
    100   uint32 id = 0;
    101   do {
    102     // Although it is unlikely, make sure that we won't cause any trouble
    103     // when the counter overflows.
    104     id = next_plugin_dispatcher_id_++;
    105   } while (id == 0 ||
    106            plugin_dispatchers_.find(id) != plugin_dispatchers_.end());
    107   plugin_dispatchers_[id] = plugin_dispatcher;
    108   return id;
    109 }
    110 
    111 void PpapiDispatcher::Unregister(uint32 plugin_dispatcher_id) {
    112   plugin_dispatchers_.erase(plugin_dispatcher_id);
    113 }
    114 
    115 IPC::Sender* PpapiDispatcher::GetBrowserSender() {
    116   return this;
    117 }
    118 
    119 std::string PpapiDispatcher::GetUILanguage() {
    120   NOTIMPLEMENTED();
    121   return std::string();
    122 }
    123 
    124 void PpapiDispatcher::PreCacheFont(const void* logfontw) {
    125   NOTIMPLEMENTED();
    126 }
    127 
    128 void PpapiDispatcher::SetActiveURL(const std::string& url) {
    129   NOTIMPLEMENTED();
    130 }
    131 
    132 PP_Resource PpapiDispatcher::CreateBrowserFont(
    133     proxy::Connection connection,
    134     PP_Instance instance,
    135     const PP_BrowserFont_Trusted_Description& desc,
    136     const Preferences& prefs) {
    137   NOTIMPLEMENTED();
    138   return 0;
    139 }
    140 
    141 bool PpapiDispatcher::OnMessageReceived(const IPC::Message& msg) {
    142   IPC_BEGIN_MESSAGE_MAP(PpapiDispatcher, msg)
    143     IPC_MESSAGE_HANDLER(PpapiMsg_InitializeNaClDispatcher,
    144                         OnMsgInitializeNaClDispatcher)
    145     // All other messages are simply forwarded to a PluginDispatcher.
    146     IPC_MESSAGE_UNHANDLED(OnPluginDispatcherMessageReceived(msg))
    147   IPC_END_MESSAGE_MAP()
    148   return true;
    149 }
    150 
    151 void PpapiDispatcher::OnChannelError() {
    152   exit(1);
    153 }
    154 
    155 bool PpapiDispatcher::Send(IPC::Message* msg) {
    156   return channel_->Send(msg);
    157 }
    158 
    159 void PpapiDispatcher::OnMsgInitializeNaClDispatcher(
    160     const PpapiNaClPluginArgs& args) {
    161   static bool command_line_and_logging_initialized = false;
    162   if (command_line_and_logging_initialized) {
    163     LOG(FATAL) << "InitializeNaClDispatcher must be called once per plugin.";
    164     return;
    165   }
    166 
    167   command_line_and_logging_initialized = true;
    168   CommandLine::Init(0, NULL);
    169   for (size_t i = 0; i < args.switch_names.size(); ++i) {
    170     DCHECK(i < args.switch_values.size());
    171     CommandLine::ForCurrentProcess()->AppendSwitchASCII(
    172         args.switch_names[i], args.switch_values[i]);
    173   }
    174   logging::LoggingSettings settings;
    175   settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
    176   logging::InitLogging(settings);
    177 
    178   proxy::PluginGlobals::Get()->set_keepalive_throttle_interval_milliseconds(
    179       args.keepalive_throttle_interval_milliseconds);
    180 
    181   // Tell the process-global GetInterface which interfaces it can return to the
    182   // plugin.
    183   proxy::InterfaceList::SetProcessGlobalPermissions(args.permissions);
    184 
    185   int32_t error = ::PPP_InitializeModule(
    186       0 /* module */,
    187       &proxy::PluginDispatcher::GetBrowserInterface);
    188   if (error)
    189     ::exit(error);
    190 
    191   proxy::PluginDispatcher* dispatcher =
    192       new proxy::PluginDispatcher(::PPP_GetInterface, args.permissions,
    193                                   args.off_the_record);
    194   IPC::ChannelHandle channel_handle(
    195       "nacl",
    196       base::FileDescriptor(renderer_ipc_fd_, false));
    197   if (!dispatcher->InitPluginWithChannel(this, base::kNullProcessId,
    198                                          channel_handle, false)) {
    199     delete dispatcher;
    200     return;
    201   }
    202   // From here, the dispatcher will manage its own lifetime according to the
    203   // lifetime of the attached channel.
    204 
    205   // Notify the renderer process, if necessary.
    206   ManifestService* manifest_service = GetManifestService();
    207   if (manifest_service)
    208     manifest_service->StartupInitializationComplete();
    209 }
    210 
    211 void PpapiDispatcher::OnPluginDispatcherMessageReceived(
    212     const IPC::Message& msg) {
    213   // The first parameter should be a plugin dispatcher ID.
    214   PickleIterator iter(msg);
    215   uint32 id = 0;
    216   if (!msg.ReadUInt32(&iter, &id)) {
    217     NOTREACHED();
    218     return;
    219   }
    220   std::map<uint32, proxy::PluginDispatcher*>::iterator dispatcher =
    221       plugin_dispatchers_.find(id);
    222   if (dispatcher != plugin_dispatchers_.end())
    223     dispatcher->second->OnMessageReceived(msg);
    224 }
    225 
    226 }  // namespace ppapi
    227