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 "content/renderer/pepper/host_globals.h" 6 7 #include <limits> 8 9 #include "base/command_line.h" 10 #include "base/logging.h" 11 #include "base/rand_util.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/task_runner.h" 14 #include "content/public/common/content_switches.h" 15 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 16 #include "content/renderer/pepper/plugin_module.h" 17 #include "content/renderer/render_thread_impl.h" 18 #include "ppapi/shared_impl/api_id.h" 19 #include "ppapi/shared_impl/id_assignment.h" 20 #include "ppapi/shared_impl/proxy_lock.h" 21 #include "third_party/WebKit/public/platform/WebString.h" 22 #include "third_party/WebKit/public/web/WebConsoleMessage.h" 23 #include "third_party/WebKit/public/web/WebDocument.h" 24 #include "third_party/WebKit/public/web/WebElement.h" 25 #include "third_party/WebKit/public/web/WebFrame.h" 26 #include "third_party/WebKit/public/web/WebPluginContainer.h" 27 28 using ppapi::CheckIdType; 29 using ppapi::MakeTypedId; 30 using ppapi::PPIdType; 31 using ppapi::ResourceTracker; 32 using blink::WebConsoleMessage; 33 using blink::WebString; 34 35 namespace content { 36 37 namespace { 38 39 typedef std::set<blink::WebPluginContainer*> ContainerSet; 40 41 // Adds all WebPluginContainers associated with the given module to the set. 42 void GetAllContainersForModule(PluginModule* module, 43 ContainerSet* containers) { 44 const PluginModule::PluginInstanceSet& instances = 45 module->GetAllInstances(); 46 for (PluginModule::PluginInstanceSet::const_iterator i = instances.begin(); 47 i != instances.end(); ++i) 48 containers->insert((*i)->container()); 49 } 50 51 WebConsoleMessage::Level LogLevelToWebLogLevel(PP_LogLevel level) { 52 switch (level) { 53 case PP_LOGLEVEL_TIP: 54 return WebConsoleMessage::LevelDebug; 55 case PP_LOGLEVEL_LOG: 56 return WebConsoleMessage::LevelLog; 57 case PP_LOGLEVEL_WARNING: 58 return WebConsoleMessage::LevelWarning; 59 case PP_LOGLEVEL_ERROR: 60 default: 61 return WebConsoleMessage::LevelError; 62 } 63 } 64 65 WebConsoleMessage MakeLogMessage(PP_LogLevel level, 66 const std::string& source, 67 const std::string& message) { 68 std::string result = source; 69 if (!result.empty()) 70 result.append(": "); 71 result.append(message); 72 return WebConsoleMessage(LogLevelToWebLogLevel(level), 73 WebString(UTF8ToUTF16(result))); 74 } 75 76 } // namespace 77 78 HostGlobals* HostGlobals::host_globals_ = NULL; 79 80 HostGlobals::HostGlobals() 81 : ppapi::PpapiGlobals(), 82 resource_tracker_(ResourceTracker::SINGLE_THREADED) { 83 DCHECK(!host_globals_); 84 host_globals_ = this; 85 // We do not support calls off of the main thread on the host side, and thus 86 // do not lock. 87 ppapi::ProxyLock::DisableLocking(); 88 } 89 90 HostGlobals::~HostGlobals() { 91 DCHECK(host_globals_ == this || !host_globals_); 92 host_globals_ = NULL; 93 } 94 95 ppapi::ResourceTracker* HostGlobals::GetResourceTracker() { 96 return &resource_tracker_; 97 } 98 99 ppapi::VarTracker* HostGlobals::GetVarTracker() { 100 return &host_var_tracker_; 101 } 102 103 ppapi::CallbackTracker* HostGlobals::GetCallbackTrackerForInstance( 104 PP_Instance instance) { 105 InstanceMap::iterator found = instance_map_.find(instance); 106 if (found == instance_map_.end()) 107 return NULL; 108 return found->second->module()->GetCallbackTracker().get(); 109 } 110 111 ppapi::thunk::PPB_Instance_API* HostGlobals::GetInstanceAPI( 112 PP_Instance instance) { 113 // The InstanceAPI is just implemented by the PluginInstance object. 114 return GetInstance(instance); 115 } 116 117 ppapi::thunk::ResourceCreationAPI* HostGlobals::GetResourceCreationAPI( 118 PP_Instance pp_instance) { 119 PepperPluginInstanceImpl* instance = GetInstance(pp_instance); 120 if (!instance) 121 return NULL; 122 return &instance->resource_creation(); 123 } 124 125 PP_Module HostGlobals::GetModuleForInstance(PP_Instance instance) { 126 PepperPluginInstanceImpl* inst = GetInstance(instance); 127 if (!inst) 128 return 0; 129 return inst->module()->pp_module(); 130 } 131 132 std::string HostGlobals::GetCmdLine() { 133 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 134 switches::kPpapiFlashArgs); 135 } 136 137 void HostGlobals::PreCacheFontForFlash(const void* logfontw) { 138 // Not implemented in-process. 139 } 140 141 void HostGlobals::LogWithSource(PP_Instance instance, 142 PP_LogLevel level, 143 const std::string& source, 144 const std::string& value) { 145 PepperPluginInstanceImpl* instance_object = 146 HostGlobals::Get()->GetInstance(instance); 147 if (instance_object) { 148 instance_object->container()->element().document().frame()-> 149 addMessageToConsole(MakeLogMessage(level, source, value)); 150 } else { 151 BroadcastLogWithSource(0, level, source, value); 152 } 153 } 154 155 void HostGlobals::BroadcastLogWithSource(PP_Module pp_module, 156 PP_LogLevel level, 157 const std::string& source, 158 const std::string& value) { 159 // Get the unique containers associated with the broadcast. This prevents us 160 // from sending the same message to the same console when there are two 161 // instances on the page. 162 ContainerSet containers; 163 PluginModule* module = GetModule(pp_module); 164 if (module) { 165 GetAllContainersForModule(module, &containers); 166 } else { 167 // Unknown module, get containers for all modules. 168 for (ModuleMap::const_iterator i = module_map_.begin(); 169 i != module_map_.end(); ++i) { 170 GetAllContainersForModule(i->second, &containers); 171 } 172 } 173 174 WebConsoleMessage message = MakeLogMessage(level, source, value); 175 for (ContainerSet::iterator i = containers.begin(); 176 i != containers.end(); ++i) 177 (*i)->element().document().frame()->addMessageToConsole(message); 178 } 179 180 base::TaskRunner* HostGlobals::GetFileTaskRunner() { 181 return RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get(); 182 } 183 184 ppapi::MessageLoopShared* HostGlobals::GetCurrentMessageLoop() { 185 return NULL; 186 } 187 188 PP_Module HostGlobals::AddModule(PluginModule* module) { 189 #ifndef NDEBUG 190 // Make sure we're not adding one more than once. 191 for (ModuleMap::const_iterator i = module_map_.begin(); 192 i != module_map_.end(); ++i) 193 DCHECK(i->second != module); 194 #endif 195 196 // See AddInstance. 197 PP_Module new_module; 198 do { 199 new_module = MakeTypedId(static_cast<PP_Module>(base::RandUint64()), 200 ppapi::PP_ID_TYPE_MODULE); 201 } while (!new_module || 202 module_map_.find(new_module) != module_map_.end()); 203 module_map_[new_module] = module; 204 return new_module; 205 } 206 207 void HostGlobals::ModuleDeleted(PP_Module module) { 208 DLOG_IF(ERROR, !CheckIdType(module, ppapi::PP_ID_TYPE_MODULE)) 209 << module << " is not a PP_Module."; 210 ModuleMap::iterator found = module_map_.find(module); 211 if (found == module_map_.end()) { 212 NOTREACHED(); 213 return; 214 } 215 module_map_.erase(found); 216 } 217 218 PluginModule* HostGlobals::GetModule(PP_Module module) { 219 DLOG_IF(ERROR, !CheckIdType(module, ppapi::PP_ID_TYPE_MODULE)) 220 << module << " is not a PP_Module."; 221 ModuleMap::iterator found = module_map_.find(module); 222 if (found == module_map_.end()) 223 return NULL; 224 return found->second; 225 } 226 227 PP_Instance HostGlobals::AddInstance(PepperPluginInstanceImpl* instance) { 228 DCHECK(instance_map_.find(instance->pp_instance()) == instance_map_.end()); 229 230 // Use a random number for the instance ID. This helps prevent some 231 // accidents. See also AddModule below. 232 // 233 // Need to make sure the random number isn't a duplicate or 0. 234 PP_Instance new_instance; 235 do { 236 new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()), 237 ppapi::PP_ID_TYPE_INSTANCE); 238 } while (!new_instance || 239 instance_map_.find(new_instance) != instance_map_.end() || 240 !instance->module()->ReserveInstanceID(new_instance)); 241 242 instance_map_[new_instance] = instance; 243 244 resource_tracker_.DidCreateInstance(new_instance); 245 return new_instance; 246 } 247 248 void HostGlobals::InstanceDeleted(PP_Instance instance) { 249 resource_tracker_.DidDeleteInstance(instance); 250 host_var_tracker_.DidDeleteInstance(instance); 251 instance_map_.erase(instance); 252 } 253 254 void HostGlobals::InstanceCrashed(PP_Instance instance) { 255 resource_tracker_.DidDeleteInstance(instance); 256 host_var_tracker_.DidDeleteInstance(instance); 257 } 258 259 PepperPluginInstanceImpl* HostGlobals::GetInstance(PP_Instance instance) { 260 DLOG_IF(ERROR, !CheckIdType(instance, ppapi::PP_ID_TYPE_INSTANCE)) 261 << instance << " is not a PP_Instance."; 262 InstanceMap::iterator found = instance_map_.find(instance); 263 if (found == instance_map_.end()) 264 return NULL; 265 return found->second; 266 } 267 268 bool HostGlobals::IsHostGlobals() const { 269 return true; 270 } 271 272 } // namespace content 273