Home | History | Annotate | Download | only in pepper
      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/pepper_plugin_registry.h"
      6 
      7 #include "base/logging.h"
      8 #include "content/common/pepper_plugin_list.h"
      9 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
     10 #include "content/renderer/pepper/plugin_module.h"
     11 #include "ppapi/shared_impl/ppapi_permissions.h"
     12 
     13 namespace content {
     14 
     15 // static
     16 PepperPluginRegistry* PepperPluginRegistry::GetInstance() {
     17   static PepperPluginRegistry* registry = NULL;
     18   // This object leaks.  It is a temporary hack to work around a crash.
     19   // http://code.google.com/p/chromium/issues/detail?id=63234
     20   if (!registry) {
     21     registry = new PepperPluginRegistry;
     22     registry->Initialize();
     23   }
     24   return registry;
     25 }
     26 
     27 const PepperPluginInfo* PepperPluginRegistry::GetInfoForPlugin(
     28     const WebPluginInfo& info) {
     29   for (size_t i = 0; i < plugin_list_.size(); ++i) {
     30     if (info.path == plugin_list_[i].path)
     31       return &plugin_list_[i];
     32   }
     33   // We did not find the plugin in our list. But wait! the plugin can also
     34   // be a latecomer, as it happens with pepper flash. This information
     35   // is actually in |info| and we can use it to construct it and add it to
     36   // the list. This same deal needs to be done in the browser side in
     37   // PluginService.
     38   PepperPluginInfo plugin;
     39   if (!MakePepperPluginInfo(info, &plugin))
     40     return NULL;
     41 
     42   plugin_list_.push_back(plugin);
     43   return &plugin_list_[plugin_list_.size() - 1];
     44 }
     45 
     46 PluginModule* PepperPluginRegistry::GetLiveModule(const base::FilePath& path) {
     47   NonOwningModuleMap::iterator module_iter = live_modules_.find(path);
     48   if (module_iter == live_modules_.end())
     49     return NULL;
     50 
     51   // Check the instances for the module to see if they've all been Delete()d.
     52   // We don't want to return a PluginModule in that case, since the plugin may
     53   // have exited already.
     54   const PluginModule::PluginInstanceSet& instance_set =
     55       module_iter->second->GetAllInstances();
     56 
     57   // If instance_set is empty, InstanceCreated() hasn't been called yet, so
     58   // it's safe to return the PluginModule.
     59   if (instance_set.empty())
     60     return module_iter->second;
     61 
     62   PluginModule::PluginInstanceSet::const_iterator instance_iter =
     63       instance_set.begin();
     64   while (instance_iter != instance_set.end()) {
     65     if (!(*instance_iter)->is_deleted())
     66       return module_iter->second;
     67     ++instance_iter;
     68   }
     69   return NULL;
     70 }
     71 
     72 void PepperPluginRegistry::AddLiveModule(const base::FilePath& path,
     73                                          PluginModule* module) {
     74   DCHECK(live_modules_.find(path) == live_modules_.end());
     75   live_modules_[path] = module;
     76 }
     77 
     78 void PepperPluginRegistry::PluginModuleDead(PluginModule* dead_module) {
     79   // DANGER: Don't dereference the dead_module pointer! It may be in the
     80   // process of being deleted.
     81 
     82   // Modules aren't destroyed very often and there are normally at most a
     83   // couple of them. So for now we just do a brute-force search.
     84   for (NonOwningModuleMap::iterator i = live_modules_.begin();
     85        i != live_modules_.end();
     86        ++i) {
     87     if (i->second == dead_module) {
     88       live_modules_.erase(i);
     89       return;
     90     }
     91   }
     92   // Can occur in tests.
     93 }
     94 
     95 PepperPluginRegistry::~PepperPluginRegistry() {
     96   // Explicitly clear all preloaded modules first. This will cause callbacks
     97   // to erase these modules from the live_modules_ list, and we don't want
     98   // that to happen implicitly out-of-order.
     99   preloaded_modules_.clear();
    100 
    101   DCHECK(live_modules_.empty());
    102 }
    103 
    104 PepperPluginRegistry::PepperPluginRegistry() {}
    105 
    106 void PepperPluginRegistry::Initialize() {
    107   ComputePepperPluginList(&plugin_list_);
    108 
    109   // Note that in each case, AddLiveModule must be called before completing
    110   // initialization. If we bail out (in the continue clauses) before saving
    111   // the initialized module, it will still try to unregister itself in its
    112   // destructor.
    113   for (size_t i = 0; i < plugin_list_.size(); i++) {
    114     const PepperPluginInfo& current = plugin_list_[i];
    115     if (current.is_out_of_process)
    116       continue;  // Out of process plugins need no special pre-initialization.
    117 
    118     scoped_refptr<PluginModule> module =
    119         new PluginModule(current.name,
    120                          current.path,
    121                          ppapi::PpapiPermissions(current.permissions));
    122     AddLiveModule(current.path, module.get());
    123     if (current.is_internal) {
    124       if (!module->InitAsInternalPlugin(current.internal_entry_points)) {
    125         DVLOG(1) << "Failed to load pepper module: " << current.path.value();
    126         continue;
    127       }
    128     } else {
    129       // Preload all external plugins we're not running out of process.
    130       if (!module->InitAsLibrary(current.path)) {
    131         DVLOG(1) << "Failed to load pepper module: " << current.path.value();
    132         continue;
    133       }
    134     }
    135     preloaded_modules_[current.path] = module;
    136   }
    137 }
    138 
    139 }  // namespace content
    140