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