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