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
13namespace content {
14
15// static
16PepperPluginRegistry* 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
27const 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
46PluginModule* 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
72void 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
78void 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
95PepperPluginRegistry::~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
104PepperPluginRegistry::PepperPluginRegistry() {}
105
106void 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.version,
121                         current.path,
122                         ppapi::PpapiPermissions(current.permissions));
123    AddLiveModule(current.path, module.get());
124    if (current.is_internal) {
125      if (!module->InitAsInternalPlugin(current.internal_entry_points)) {
126        DVLOG(1) << "Failed to load pepper module: " << current.path.value();
127        continue;
128      }
129    } else {
130      // Preload all external plugins we're not running out of process.
131      if (!module->InitAsLibrary(current.path)) {
132        DVLOG(1) << "Failed to load pepper module: " << current.path.value();
133        continue;
134      }
135    }
136    preloaded_modules_[current.path] = module;
137  }
138}
139
140}  // namespace content
141