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 37LogFunctionMap 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 46namespace ppapi { 47 48PpapiDispatcher::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 75base::MessageLoopProxy* PpapiDispatcher::GetIPCMessageLoop() { 76 return message_loop_.get(); 77} 78 79base::WaitableEvent* PpapiDispatcher::GetShutdownEvent() { 80 return shutdown_event_; 81} 82 83IPC::PlatformFileForTransit PpapiDispatcher::ShareHandleWithRemote( 84 base::PlatformFile handle, 85 base::ProcessId peer_pid, 86 bool should_close_source) { 87 return IPC::InvalidPlatformFileForTransit(); 88} 89 90std::set<PP_Instance>* PpapiDispatcher::GetGloballySeenInstanceIDSet() { 91 return &instances_; 92} 93 94uint32 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 111void PpapiDispatcher::Unregister(uint32 plugin_dispatcher_id) { 112 plugin_dispatchers_.erase(plugin_dispatcher_id); 113} 114 115IPC::Sender* PpapiDispatcher::GetBrowserSender() { 116 return this; 117} 118 119std::string PpapiDispatcher::GetUILanguage() { 120 NOTIMPLEMENTED(); 121 return std::string(); 122} 123 124void PpapiDispatcher::PreCacheFont(const void* logfontw) { 125 NOTIMPLEMENTED(); 126} 127 128void PpapiDispatcher::SetActiveURL(const std::string& url) { 129 NOTIMPLEMENTED(); 130} 131 132PP_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 141bool 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 151void PpapiDispatcher::OnChannelError() { 152 exit(1); 153} 154 155bool PpapiDispatcher::Send(IPC::Message* msg) { 156 return channel_->Send(msg); 157} 158 159void 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 211void 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