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 <map> 6 #include <set> 7 8 #include "build/build_config.h" 9 // Need to include this before most other files because it defines 10 // IPC_MESSAGE_LOG_ENABLED. We need to use it to define 11 // IPC_MESSAGE_MACROS_LOG_ENABLED so ppapi_messages.h will generate the 12 // ViewMsgLog et al. functions. 13 14 #include "base/command_line.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/synchronization/waitable_event.h" 17 #include "base/threading/thread.h" 18 #include "components/tracing/child_trace_message_filter.h" 19 #include "ipc/ipc_channel_handle.h" 20 #include "ipc/ipc_logging.h" 21 #include "ipc/ipc_message.h" 22 #include "native_client/src/shared/srpc/nacl_srpc.h" 23 #include "native_client/src/untrusted/irt/irt_ppapi.h" 24 #include "ppapi/c/ppp.h" 25 #include "ppapi/c/ppp_instance.h" 26 #include "ppapi/native_client/src/shared/ppapi_proxy/ppruntime.h" 27 #include "ppapi/proxy/plugin_dispatcher.h" 28 #include "ppapi/proxy/plugin_globals.h" 29 #include "ppapi/proxy/plugin_message_filter.h" 30 #include "ppapi/proxy/plugin_proxy_delegate.h" 31 #include "ppapi/proxy/resource_reply_thread_registrar.h" 32 #include "ppapi/shared_impl/ppb_audio_shared.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 // This must match up with NACL_CHROME_INITIAL_IPC_DESC, 47 // defined in sel_main_chrome.h 48 #define NACL_IPC_FD 6 49 50 using ppapi::proxy::PluginDispatcher; 51 using ppapi::proxy::PluginGlobals; 52 using ppapi::proxy::PluginProxyDelegate; 53 using ppapi::proxy::ProxyChannel; 54 using ppapi::proxy::SerializedHandle; 55 56 namespace { 57 58 // This class manages communication between the plugin and the browser, and 59 // manages the PluginDispatcher instances for communication between the plugin 60 // and the renderer. 61 class PpapiDispatcher : public ProxyChannel, 62 public PluginDispatcher::PluginDelegate, 63 public PluginProxyDelegate { 64 public: 65 explicit PpapiDispatcher(scoped_refptr<base::MessageLoopProxy> io_loop); 66 67 // PluginDispatcher::PluginDelegate implementation. 68 virtual base::MessageLoopProxy* GetIPCMessageLoop() OVERRIDE; 69 virtual base::WaitableEvent* GetShutdownEvent() OVERRIDE; 70 virtual IPC::PlatformFileForTransit ShareHandleWithRemote( 71 base::PlatformFile handle, 72 base::ProcessId peer_pid, 73 bool should_close_source) OVERRIDE; 74 virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() OVERRIDE; 75 virtual uint32 Register(PluginDispatcher* plugin_dispatcher) OVERRIDE; 76 virtual void Unregister(uint32 plugin_dispatcher_id) OVERRIDE; 77 78 // PluginProxyDelegate implementation. 79 virtual IPC::Sender* GetBrowserSender() OVERRIDE; 80 virtual std::string GetUILanguage() OVERRIDE; 81 virtual void PreCacheFont(const void* logfontw) OVERRIDE; 82 virtual void SetActiveURL(const std::string& url) OVERRIDE; 83 virtual PP_Resource CreateBrowserFont( 84 ppapi::proxy::Connection connection, 85 PP_Instance instance, 86 const PP_BrowserFont_Trusted_Description& desc, 87 const ppapi::Preferences& prefs) OVERRIDE; 88 89 // IPC::Listener implementation. 90 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 91 92 private: 93 void OnMsgCreateNaClChannel(int renderer_id, 94 const ppapi::PpapiNaClChannelArgs& args, 95 SerializedHandle handle); 96 void OnPluginDispatcherMessageReceived(const IPC::Message& msg); 97 98 std::set<PP_Instance> instances_; 99 std::map<uint32, PluginDispatcher*> plugin_dispatchers_; 100 uint32 next_plugin_dispatcher_id_; 101 scoped_refptr<base::MessageLoopProxy> message_loop_; 102 base::WaitableEvent shutdown_event_; 103 }; 104 105 PpapiDispatcher::PpapiDispatcher(scoped_refptr<base::MessageLoopProxy> io_loop) 106 : next_plugin_dispatcher_id_(0), 107 message_loop_(io_loop), 108 shutdown_event_(true, false) { 109 IPC::ChannelHandle channel_handle( 110 "NaCl IPC", base::FileDescriptor(NACL_IPC_FD, false)); 111 // We don't have/need a PID since handle sharing happens outside of the 112 // NaCl sandbox. 113 InitWithChannel(this, base::kNullProcessId, channel_handle, 114 false); // Channel is server. 115 channel()->AddFilter(new ppapi::proxy::PluginMessageFilter( 116 NULL, PluginGlobals::Get()->resource_reply_thread_registrar())); 117 channel()->AddFilter( 118 new tracing::ChildTraceMessageFilter(message_loop_.get())); 119 } 120 121 base::MessageLoopProxy* PpapiDispatcher::GetIPCMessageLoop() { 122 return message_loop_.get(); 123 } 124 125 base::WaitableEvent* PpapiDispatcher::GetShutdownEvent() { 126 return &shutdown_event_; 127 } 128 129 IPC::PlatformFileForTransit PpapiDispatcher::ShareHandleWithRemote( 130 base::PlatformFile handle, 131 base::ProcessId peer_pid, 132 bool should_close_source) { 133 return IPC::InvalidPlatformFileForTransit(); 134 } 135 136 std::set<PP_Instance>* PpapiDispatcher::GetGloballySeenInstanceIDSet() { 137 return &instances_; 138 } 139 140 uint32 PpapiDispatcher::Register(PluginDispatcher* plugin_dispatcher) { 141 if (!plugin_dispatcher || 142 plugin_dispatchers_.size() >= std::numeric_limits<uint32>::max()) { 143 return 0; 144 } 145 146 uint32 id = 0; 147 do { 148 // Although it is unlikely, make sure that we won't cause any trouble 149 // when the counter overflows. 150 id = next_plugin_dispatcher_id_++; 151 } while (id == 0 || 152 plugin_dispatchers_.find(id) != plugin_dispatchers_.end()); 153 plugin_dispatchers_[id] = plugin_dispatcher; 154 return id; 155 } 156 157 void PpapiDispatcher::Unregister(uint32 plugin_dispatcher_id) { 158 plugin_dispatchers_.erase(plugin_dispatcher_id); 159 } 160 161 IPC::Sender* PpapiDispatcher::GetBrowserSender() { 162 return this; 163 } 164 165 std::string PpapiDispatcher::GetUILanguage() { 166 NOTIMPLEMENTED(); 167 return std::string(); 168 } 169 170 void PpapiDispatcher::PreCacheFont(const void* logfontw) { 171 NOTIMPLEMENTED(); 172 } 173 174 void PpapiDispatcher::SetActiveURL(const std::string& url) { 175 NOTIMPLEMENTED(); 176 } 177 178 PP_Resource PpapiDispatcher::CreateBrowserFont( 179 ppapi::proxy::Connection connection, 180 PP_Instance instance, 181 const PP_BrowserFont_Trusted_Description& desc, 182 const ppapi::Preferences& prefs) { 183 NOTIMPLEMENTED(); 184 return 0; 185 } 186 187 bool PpapiDispatcher::OnMessageReceived(const IPC::Message& msg) { 188 IPC_BEGIN_MESSAGE_MAP(PpapiDispatcher, msg) 189 IPC_MESSAGE_HANDLER(PpapiMsg_CreateNaClChannel, OnMsgCreateNaClChannel) 190 // All other messages are simply forwarded to a PluginDispatcher. 191 IPC_MESSAGE_UNHANDLED(OnPluginDispatcherMessageReceived(msg)) 192 IPC_END_MESSAGE_MAP() 193 return true; 194 } 195 196 void PpapiDispatcher::OnMsgCreateNaClChannel( 197 int renderer_id, 198 const ppapi::PpapiNaClChannelArgs& args, 199 SerializedHandle handle) { 200 static bool command_line_and_logging_initialized = false; 201 if (!command_line_and_logging_initialized) { 202 CommandLine::Init(0, NULL); 203 for (size_t i = 0; i < args.switch_names.size(); ++i) { 204 DCHECK(i < args.switch_values.size()); 205 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 206 args.switch_names[i], args.switch_values[i]); 207 } 208 logging::LoggingSettings settings; 209 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; 210 logging::InitLogging(settings); 211 command_line_and_logging_initialized = true; 212 } 213 // Tell the process-global GetInterface which interfaces it can return to the 214 // plugin. 215 ppapi::proxy::InterfaceList::SetProcessGlobalPermissions( 216 args.permissions); 217 ppapi::proxy::InterfaceList::SetSupportsDevChannel( 218 args.supports_dev_channel); 219 220 int32_t error = ::PPP_InitializeModule( 221 0 /* module */, 222 &ppapi::proxy::PluginDispatcher::GetBrowserInterface); 223 if (error) 224 ::exit(error); 225 226 PluginDispatcher* dispatcher = 227 new PluginDispatcher(::PPP_GetInterface, args.permissions, 228 args.off_the_record); 229 // The channel handle's true name is not revealed here. 230 IPC::ChannelHandle channel_handle("nacl", handle.descriptor()); 231 if (!dispatcher->InitPluginWithChannel(this, base::kNullProcessId, 232 channel_handle, false)) { 233 delete dispatcher; 234 return; 235 } 236 // From here, the dispatcher will manage its own lifetime according to the 237 // lifetime of the attached channel. 238 } 239 240 void PpapiDispatcher::OnPluginDispatcherMessageReceived( 241 const IPC::Message& msg) { 242 // The first parameter should be a plugin dispatcher ID. 243 PickleIterator iter(msg); 244 uint32 id = 0; 245 if (!msg.ReadUInt32(&iter, &id)) { 246 NOTREACHED(); 247 return; 248 } 249 std::map<uint32, ppapi::proxy::PluginDispatcher*>::iterator dispatcher = 250 plugin_dispatchers_.find(id); 251 if (dispatcher != plugin_dispatchers_.end()) 252 dispatcher->second->OnMessageReceived(msg); 253 } 254 255 } // namespace 256 257 void PpapiPluginRegisterThreadCreator( 258 const struct PP_ThreadFunctions* thread_functions) { 259 // Initialize all classes that need to create threads that call back into 260 // user code. 261 ppapi::PPB_Audio_Shared::SetThreadFunctions(thread_functions); 262 } 263 264 int PpapiPluginMain() { 265 // Though it isn't referenced here, we must instantiate an AtExitManager. 266 base::AtExitManager exit_manager; 267 base::MessageLoop loop; 268 IPC::Logging::set_log_function_map(&g_log_function_mapping); 269 ppapi::proxy::PluginGlobals plugin_globals; 270 base::Thread io_thread("Chrome_NaClIOThread"); 271 base::Thread::Options options; 272 options.message_loop_type = base::MessageLoop::TYPE_IO; 273 io_thread.StartWithOptions(options); 274 275 // Start up the SRPC server on another thread. Otherwise, when it blocks 276 // on an RPC, the PPAPI proxy will hang. Do this before we initialize the 277 // module and start the PPAPI proxy so that the NaCl plugin can continue 278 // loading the app. 279 static struct NaClSrpcHandlerDesc srpc_methods[] = { { NULL, NULL } }; 280 if (!NaClSrpcAcceptClientOnThread(srpc_methods)) { 281 return 1; 282 } 283 284 PpapiDispatcher ppapi_dispatcher(io_thread.message_loop_proxy()); 285 plugin_globals.set_plugin_proxy_delegate(&ppapi_dispatcher); 286 287 loop.Run(); 288 289 return 0; 290 } 291