| OLD | NEW | 
|---|
|  | (Empty) | 
| 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/browser/plugin_loader_posix.h" |  | 
| 6 |  | 
| 7 #include "base/bind.h" |  | 
| 8 #include "base/location.h" |  | 
| 9 #include "base/metrics/histogram.h" |  | 
| 10 #include "base/single_thread_task_runner.h" |  | 
| 11 #include "base/thread_task_runner_handle.h" |  | 
| 12 #include "content/browser/utility_process_host_impl.h" |  | 
| 13 #include "content/common/child_process_host_impl.h" |  | 
| 14 #include "content/common/plugin_list.h" |  | 
| 15 #include "content/common/utility_messages.h" |  | 
| 16 #include "content/public/browser/browser_thread.h" |  | 
| 17 #include "content/public/browser/plugin_service.h" |  | 
| 18 #include "content/public/browser/user_metrics.h" |  | 
| 19 |  | 
| 20 namespace content { |  | 
| 21 |  | 
| 22 PluginLoaderPosix::PluginLoaderPosix() |  | 
| 23     : next_load_index_(0), loading_plugins_(false) { |  | 
| 24 } |  | 
| 25 |  | 
| 26 void PluginLoaderPosix::GetPlugins( |  | 
| 27     const PluginService::GetPluginsCallback& callback) { |  | 
| 28   DCHECK_CURRENTLY_ON(BrowserThread::IO); |  | 
| 29 |  | 
| 30   std::vector<WebPluginInfo> cached_plugins; |  | 
| 31   if (PluginList::Singleton()->GetPluginsNoRefresh(&cached_plugins)) { |  | 
| 32     // Can't assume the caller is reentrant. |  | 
| 33     base::ThreadTaskRunnerHandle::Get()->PostTask( |  | 
| 34         FROM_HERE, base::Bind(callback, cached_plugins)); |  | 
| 35     return; |  | 
| 36   } |  | 
| 37 |  | 
| 38   if (!loading_plugins_) { |  | 
| 39     loading_plugins_ = true; |  | 
| 40     callbacks_.push_back(callback); |  | 
| 41 |  | 
| 42     // When |loading_plugins_| is set to false, this instance must call |  | 
| 43     // SetPlugins(). |  | 
| 44     PluginList::Singleton()->PrepareForPluginLoading(); |  | 
| 45 |  | 
| 46     BrowserThread::PostTask(BrowserThread::FILE, |  | 
| 47                             FROM_HERE, |  | 
| 48                             base::Bind(&PluginLoaderPosix::GetPluginsToLoad, |  | 
| 49                                        make_scoped_refptr(this))); |  | 
| 50   } else { |  | 
| 51     // If we are currently loading plugins, the plugin list might have been |  | 
| 52     // invalidated in the mean time, or might get invalidated before we finish. |  | 
| 53     // We'll wait until we have finished the current run, then try to get them |  | 
| 54     // again from the plugin list. If it has indeed been invalidated, it will |  | 
| 55     // restart plugin loading, otherwise it will immediately run the callback. |  | 
| 56     callbacks_.push_back(base::Bind(&PluginLoaderPosix::GetPluginsWrapper, |  | 
| 57                                     make_scoped_refptr(this), callback)); |  | 
| 58   } |  | 
| 59 } |  | 
| 60 |  | 
| 61 bool PluginLoaderPosix::OnMessageReceived(const IPC::Message& message) { |  | 
| 62   bool handled = true; |  | 
| 63   IPC_BEGIN_MESSAGE_MAP(PluginLoaderPosix, message) |  | 
| 64     IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadedPlugin, OnPluginLoaded) |  | 
| 65     IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadPluginFailed, OnPluginLoadFailed) |  | 
| 66     IPC_MESSAGE_UNHANDLED(handled = false) |  | 
| 67   IPC_END_MESSAGE_MAP() |  | 
| 68   return handled; |  | 
| 69 } |  | 
| 70 |  | 
| 71 void PluginLoaderPosix::OnProcessCrashed(int exit_code) { |  | 
| 72   RecordAction( |  | 
| 73       base::UserMetricsAction("PluginLoaderPosix.UtilityProcessCrashed")); |  | 
| 74 |  | 
| 75   if (next_load_index_ == canonical_list_.size()) { |  | 
| 76     // How this case occurs is unknown. See crbug.com/111935. |  | 
| 77     canonical_list_.clear(); |  | 
| 78   } else { |  | 
| 79     canonical_list_.erase(canonical_list_.begin(), |  | 
| 80                           canonical_list_.begin() + next_load_index_ + 1); |  | 
| 81   } |  | 
| 82 |  | 
| 83   next_load_index_ = 0; |  | 
| 84 |  | 
| 85   LoadPluginsInternal(); |  | 
| 86 } |  | 
| 87 |  | 
| 88 void PluginLoaderPosix::OnProcessLaunchFailed() { |  | 
| 89   FinishedLoadingPlugins(); |  | 
| 90 } |  | 
| 91 |  | 
| 92 bool PluginLoaderPosix::Send(IPC::Message* message) { |  | 
| 93   if (process_host_.get()) |  | 
| 94     return process_host_->Send(message); |  | 
| 95   return false; |  | 
| 96 } |  | 
| 97 |  | 
| 98 PluginLoaderPosix::~PluginLoaderPosix() { |  | 
| 99 } |  | 
| 100 |  | 
| 101 void PluginLoaderPosix::GetPluginsToLoad() { |  | 
| 102   DCHECK_CURRENTLY_ON(BrowserThread::FILE); |  | 
| 103 |  | 
| 104   base::TimeTicks start_time(base::TimeTicks::Now()); |  | 
| 105 |  | 
| 106   loaded_plugins_.clear(); |  | 
| 107   next_load_index_ = 0; |  | 
| 108 |  | 
| 109   canonical_list_.clear(); |  | 
| 110   PluginList::Singleton()->GetPluginPathsToLoad( |  | 
| 111       &canonical_list_, |  | 
| 112       PluginService::GetInstance()->NPAPIPluginsSupported()); |  | 
| 113 |  | 
| 114   internal_plugins_.clear(); |  | 
| 115   PluginList::Singleton()->GetInternalPlugins(&internal_plugins_); |  | 
| 116 |  | 
| 117   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |  | 
| 118       base::Bind(&PluginLoaderPosix::LoadPluginsInternal, |  | 
| 119                  make_scoped_refptr(this))); |  | 
| 120 |  | 
| 121   LOCAL_HISTOGRAM_TIMES("PluginLoaderPosix.GetPluginList", |  | 
| 122                         (base::TimeTicks::Now() - start_time) * |  | 
| 123                             base::Time::kMicrosecondsPerMillisecond); |  | 
| 124 } |  | 
| 125 |  | 
| 126 void PluginLoaderPosix::LoadPluginsInternal() { |  | 
| 127   DCHECK_CURRENTLY_ON(BrowserThread::IO); |  | 
| 128 |  | 
| 129   // Check if the list is empty or all plugins have already been loaded before |  | 
| 130   // forking. |  | 
| 131   if (IsFinishedLoadingPlugins()) { |  | 
| 132     FinishedLoadingPlugins(); |  | 
| 133     return; |  | 
| 134   } |  | 
| 135 |  | 
| 136   RecordAction( |  | 
| 137       base::UserMetricsAction("PluginLoaderPosix.LaunchUtilityProcess")); |  | 
| 138 |  | 
| 139   UtilityProcessHostImpl* host = new UtilityProcessHostImpl( |  | 
| 140       this, |  | 
| 141       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get()); |  | 
| 142   process_host_ = host->AsWeakPtr(); |  | 
| 143   process_host_->DisableSandbox(); |  | 
| 144 |  | 
| 145   bool launched = LaunchUtilityProcess(); |  | 
| 146   if (!launched) { |  | 
| 147     // The utility process either failed to start or failed to receive the IPC. |  | 
| 148     // This process will never receive any callbacks for OnPluginLoaded() or |  | 
| 149     // OnPluginLoadFailed(). |  | 
| 150     FinishedLoadingPlugins(); |  | 
| 151   } |  | 
| 152 } |  | 
| 153 |  | 
| 154 void PluginLoaderPosix::GetPluginsWrapper( |  | 
| 155     const PluginService::GetPluginsCallback& callback, |  | 
| 156     const std::vector<WebPluginInfo>& plugins_unused) { |  | 
| 157   // We are being called after plugin loading has finished, but we don't know |  | 
| 158   // whether the plugin list has been invalidated in the mean time |  | 
| 159   // (and therefore |plugins| might already be stale). So we simply ignore it |  | 
| 160   // and call regular GetPlugins() instead. |  | 
| 161   GetPlugins(callback); |  | 
| 162 } |  | 
| 163 |  | 
| 164 void PluginLoaderPosix::OnPluginLoaded(uint32_t index, |  | 
| 165                                        const WebPluginInfo& plugin) { |  | 
| 166   if (index != next_load_index_) { |  | 
| 167     LOG(ERROR) << "Received unexpected plugin load message for " |  | 
| 168                << plugin.path.value() << "; index=" << index; |  | 
| 169     return; |  | 
| 170   } |  | 
| 171 |  | 
| 172   auto it = FindInternalPlugin(plugin.path); |  | 
| 173   if (it != internal_plugins_.end()) { |  | 
| 174     loaded_plugins_.push_back(*it); |  | 
| 175     internal_plugins_.erase(it); |  | 
| 176   } else { |  | 
| 177     loaded_plugins_.push_back(plugin); |  | 
| 178   } |  | 
| 179 |  | 
| 180   ++next_load_index_; |  | 
| 181 |  | 
| 182   if (IsFinishedLoadingPlugins()) |  | 
| 183     FinishedLoadingPlugins(); |  | 
| 184 } |  | 
| 185 |  | 
| 186 void PluginLoaderPosix::OnPluginLoadFailed(uint32_t index, |  | 
| 187                                            const base::FilePath& plugin_path) { |  | 
| 188   if (index != next_load_index_) { |  | 
| 189     LOG(ERROR) << "Received unexpected plugin load failure message for " |  | 
| 190                << plugin_path.value() << "; index=" << index; |  | 
| 191     return; |  | 
| 192   } |  | 
| 193 |  | 
| 194   ++next_load_index_; |  | 
| 195 |  | 
| 196   auto it = FindInternalPlugin(plugin_path); |  | 
| 197   if (it != internal_plugins_.end()) { |  | 
| 198     loaded_plugins_.push_back(*it); |  | 
| 199     internal_plugins_.erase(it); |  | 
| 200   } |  | 
| 201 |  | 
| 202   if (IsFinishedLoadingPlugins()) |  | 
| 203     FinishedLoadingPlugins(); |  | 
| 204 } |  | 
| 205 |  | 
| 206 std::vector<WebPluginInfo>::iterator PluginLoaderPosix::FindInternalPlugin( |  | 
| 207     const base::FilePath& plugin_path) { |  | 
| 208   return std::find_if(internal_plugins_.begin(), internal_plugins_.end(), |  | 
| 209                       [&plugin_path](const WebPluginInfo& plugin) { |  | 
| 210     return plugin.path == plugin_path; |  | 
| 211   }); |  | 
| 212 } |  | 
| 213 |  | 
| 214 bool PluginLoaderPosix::IsFinishedLoadingPlugins() { |  | 
| 215   if (canonical_list_.empty()) |  | 
| 216     return true; |  | 
| 217 |  | 
| 218   DCHECK(next_load_index_ <= canonical_list_.size()); |  | 
| 219   return next_load_index_ == canonical_list_.size(); |  | 
| 220 } |  | 
| 221 |  | 
| 222 void PluginLoaderPosix::FinishedLoadingPlugins() { |  | 
| 223   loading_plugins_ = false; |  | 
| 224   PluginList::Singleton()->SetPlugins(loaded_plugins_); |  | 
| 225 |  | 
| 226   for (auto& callback : callbacks_) { |  | 
| 227     base::ThreadTaskRunnerHandle::Get()->PostTask( |  | 
| 228         FROM_HERE, base::Bind(callback, loaded_plugins_)); |  | 
| 229   } |  | 
| 230   callbacks_.clear(); |  | 
| 231 } |  | 
| 232 |  | 
| 233 bool PluginLoaderPosix::LaunchUtilityProcess() { |  | 
| 234   return process_host_->Send(new UtilityMsg_LoadPlugins(canonical_list_)); |  | 
| 235 } |  | 
| 236 |  | 
| 237 }  // namespace content |  | 
| OLD | NEW | 
|---|