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"
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"
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
));
37 if (callbacks_
.empty()) {
38 callbacks_
.push_back(callback
);
40 PluginList::Singleton()->PrepareForPluginLoading();
42 BrowserThread::PostTask(BrowserThread::FILE,
44 base::Bind(&PluginLoaderPosix::GetPluginsToLoad
,
45 make_scoped_refptr(this)));
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
) {
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)
67 void PluginLoaderPosix::OnProcessCrashed(int exit_code
) {
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();
75 canonical_list_
.erase(canonical_list_
.begin(),
76 canonical_list_
.begin() + next_load_index_
+ 1);
81 LoadPluginsInternal();
84 bool PluginLoaderPosix::Send(IPC::Message
* message
) {
85 if (process_host_
.get())
86 return process_host_
->Send(message
);
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();
101 canonical_list_
.clear();
102 PluginList::Singleton()->GetPluginPathsToLoad(
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 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
123 if (MaybeRunPendingCallbacks())
127 base::UserMetricsAction("PluginLoaderPosix.LaunchUtilityProcess"));
129 if (load_start_time_
.is_null())
130 load_start_time_
= base::TimeTicks::Now();
132 UtilityProcessHostImpl
* host
= new UtilityProcessHostImpl(
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
);
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
;
162 if (!MaybeAddInternalPlugin(plugin
.path
))
163 loaded_plugins_
.push_back(plugin
);
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
;
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();
189 if (it
->path
== plugin_path
) {
190 loaded_plugins_
.push_back(*it
);
191 internal_plugins_
.erase(it
);
198 bool PluginLoaderPosix::MaybeRunPendingCallbacks() {
199 if (next_load_index_
< canonical_list_
.size())
202 PluginList::Singleton()->SetPlugins(loaded_plugins_
);
204 for (std::vector
<PluginService::GetPluginsCallback
>::iterator it
=
206 it
!= callbacks_
.end(); ++it
) {
207 base::MessageLoop::current()->PostTask(FROM_HERE
,
208 base::Bind(*it
, loaded_plugins_
));
212 HISTOGRAM_TIMES("PluginLoaderPosix.LoadDone",
213 (base::TimeTicks::Now() - load_start_time_
)
214 * base::Time::kMicrosecondsPerMillisecond
);
215 load_start_time_
= base::TimeTicks();
220 } // namespace content