Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / plugin_loader_posix.cc
blob22bc2b614c2599f8242540c471ea1a347ca16cb8
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.
5 #include "content/browser/plugin_loader_posix.h"
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/metrics/histogram.h"
11 #include "content/browser/utility_process_host_impl.h"
12 #include "content/common/child_process_host_impl.h"
13 #include "content/common/plugin_list.h"
14 #include "content/common/utility_messages.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/plugin_service.h"
17 #include "content/public/browser/user_metrics.h"
19 namespace content {
21 PluginLoaderPosix::PluginLoaderPosix()
22 : next_load_index_(0) {
25 void PluginLoaderPosix::GetPlugins(
26 const PluginService::GetPluginsCallback& callback) {
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
29 std::vector<WebPluginInfo> cached_plugins;
30 if (PluginList::Singleton()->GetPluginsNoRefresh(&cached_plugins)) {
31 // Can't assume the caller is reentrant.
32 base::MessageLoop::current()->PostTask(FROM_HERE,
33 base::Bind(callback, cached_plugins));
34 return;
37 if (callbacks_.empty()) {
38 callbacks_.push_back(callback);
40 PluginList::Singleton()->PrepareForPluginLoading();
42 BrowserThread::PostTask(BrowserThread::FILE,
43 FROM_HERE,
44 base::Bind(&PluginLoaderPosix::GetPluginsToLoad,
45 make_scoped_refptr(this)));
46 } else {
47 // If we are currently loading plugins, the plugin list might have been
48 // invalidated in the mean time, or might get invalidated before we finish.
49 // We'll wait until we have finished the current run, then try to get them
50 // again from the plugin list. If it has indeed been invalidated, it will
51 // restart plugin loading, otherwise it will immediately run the callback.
52 callbacks_.push_back(base::Bind(&PluginLoaderPosix::GetPluginsWrapper,
53 make_scoped_refptr(this), callback));
57 bool PluginLoaderPosix::OnMessageReceived(const IPC::Message& message) {
58 bool handled = true;
59 IPC_BEGIN_MESSAGE_MAP(PluginLoaderPosix, message)
60 IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadedPlugin, OnPluginLoaded)
61 IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadPluginFailed, OnPluginLoadFailed)
62 IPC_MESSAGE_UNHANDLED(handled = false)
63 IPC_END_MESSAGE_MAP()
64 return handled;
67 void PluginLoaderPosix::OnProcessCrashed(int exit_code) {
68 RecordAction(
69 base::UserMetricsAction("PluginLoaderPosix.UtilityProcessCrashed"));
71 if (next_load_index_ == canonical_list_.size()) {
72 // How this case occurs is unknown. See crbug.com/111935.
73 canonical_list_.clear();
74 } else {
75 canonical_list_.erase(canonical_list_.begin(),
76 canonical_list_.begin() + next_load_index_ + 1);
79 next_load_index_ = 0;
81 LoadPluginsInternal();
84 bool PluginLoaderPosix::Send(IPC::Message* message) {
85 if (process_host_.get())
86 return process_host_->Send(message);
87 return false;
90 PluginLoaderPosix::~PluginLoaderPosix() {
93 void PluginLoaderPosix::GetPluginsToLoad() {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
96 base::TimeTicks start_time(base::TimeTicks::Now());
98 loaded_plugins_.clear();
99 next_load_index_ = 0;
101 canonical_list_.clear();
102 PluginList::Singleton()->GetPluginPathsToLoad(
103 &canonical_list_,
104 PluginService::GetInstance()->NPAPIPluginsSupported());
106 internal_plugins_.clear();
107 PluginList::Singleton()->GetInternalPlugins(&internal_plugins_);
109 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
110 base::Bind(&PluginLoaderPosix::LoadPluginsInternal,
111 make_scoped_refptr(this)));
113 LOCAL_HISTOGRAM_TIMES("PluginLoaderPosix.GetPluginList",
114 (base::TimeTicks::Now() - start_time) *
115 base::Time::kMicrosecondsPerMillisecond);
118 void PluginLoaderPosix::LoadPluginsInternal() {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
121 // Check if the list is empty or all plugins have already been loaded before
122 // forking.
123 if (MaybeRunPendingCallbacks())
124 return;
126 RecordAction(
127 base::UserMetricsAction("PluginLoaderPosix.LaunchUtilityProcess"));
129 if (load_start_time_.is_null())
130 load_start_time_ = base::TimeTicks::Now();
132 UtilityProcessHostImpl* host = new UtilityProcessHostImpl(
133 this,
134 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get());
135 process_host_ = host->AsWeakPtr();
136 process_host_->DisableSandbox();
137 #if defined(OS_MACOSX)
138 host->set_child_flags(ChildProcessHost::CHILD_ALLOW_HEAP_EXECUTION);
139 #endif
141 process_host_->Send(new UtilityMsg_LoadPlugins(canonical_list_));
144 void PluginLoaderPosix::GetPluginsWrapper(
145 const PluginService::GetPluginsCallback& callback,
146 const std::vector<WebPluginInfo>& plugins_unused) {
147 // We are being called after plugin loading has finished, but we don't know
148 // whether the plugin list has been invalidated in the mean time
149 // (and therefore |plugins| might already be stale). So we simply ignore it
150 // and call regular GetPlugins() instead.
151 GetPlugins(callback);
154 void PluginLoaderPosix::OnPluginLoaded(uint32 index,
155 const WebPluginInfo& plugin) {
156 if (index != next_load_index_) {
157 LOG(ERROR) << "Received unexpected plugin load message for "
158 << plugin.path.value() << "; index=" << index;
159 return;
162 if (!MaybeAddInternalPlugin(plugin.path))
163 loaded_plugins_.push_back(plugin);
165 ++next_load_index_;
167 MaybeRunPendingCallbacks();
170 void PluginLoaderPosix::OnPluginLoadFailed(uint32 index,
171 const base::FilePath& plugin_path) {
172 if (index != next_load_index_) {
173 LOG(ERROR) << "Received unexpected plugin load failure message for "
174 << plugin_path.value() << "; index=" << index;
175 return;
178 ++next_load_index_;
180 MaybeAddInternalPlugin(plugin_path);
181 MaybeRunPendingCallbacks();
184 bool PluginLoaderPosix::MaybeAddInternalPlugin(
185 const base::FilePath& plugin_path) {
186 for (std::vector<WebPluginInfo>::iterator it = internal_plugins_.begin();
187 it != internal_plugins_.end();
188 ++it) {
189 if (it->path == plugin_path) {
190 loaded_plugins_.push_back(*it);
191 internal_plugins_.erase(it);
192 return true;
195 return false;
198 bool PluginLoaderPosix::MaybeRunPendingCallbacks() {
199 if (next_load_index_ < canonical_list_.size())
200 return false;
202 PluginList::Singleton()->SetPlugins(loaded_plugins_);
204 for (std::vector<PluginService::GetPluginsCallback>::iterator it =
205 callbacks_.begin();
206 it != callbacks_.end(); ++it) {
207 base::MessageLoop::current()->PostTask(FROM_HERE,
208 base::Bind(*it, loaded_plugins_));
210 callbacks_.clear();
212 LOCAL_HISTOGRAM_TIMES("PluginLoaderPosix.LoadDone",
213 (base::TimeTicks::Now() - load_start_time_) *
214 base::Time::kMicrosecondsPerMillisecond);
215 load_start_time_ = base::TimeTicks();
217 return true;
220 } // namespace content