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"
20 PluginLoaderPosix::PluginLoaderPosix()
21 : next_load_index_(0) {
24 void PluginLoaderPosix::LoadPlugins(
25 scoped_refptr
<base::MessageLoopProxy
> target_loop
,
26 const PluginService::GetPluginsCallback
& callback
) {
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
29 callbacks_
.push_back(PendingCallback(target_loop
, callback
));
31 if (callbacks_
.size() == 1) {
32 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
33 base::Bind(&PluginLoaderPosix::GetPluginsToLoad
, this));
37 bool PluginLoaderPosix::OnMessageReceived(const IPC::Message
& message
) {
39 IPC_BEGIN_MESSAGE_MAP(PluginLoaderPosix
, message
)
40 IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadedPlugin
, OnPluginLoaded
)
41 IPC_MESSAGE_HANDLER(UtilityHostMsg_LoadPluginFailed
, OnPluginLoadFailed
)
42 IPC_MESSAGE_UNHANDLED(handled
= false)
47 void PluginLoaderPosix::OnProcessCrashed(int exit_code
) {
48 if (next_load_index_
== canonical_list_
.size()) {
49 // How this case occurs is unknown. See crbug.com/111935.
50 canonical_list_
.clear();
52 canonical_list_
.erase(canonical_list_
.begin(),
53 canonical_list_
.begin() + next_load_index_
+ 1);
58 LoadPluginsInternal();
61 bool PluginLoaderPosix::Send(IPC::Message
* message
) {
62 if (process_host_
.get())
63 return process_host_
->Send(message
);
67 PluginLoaderPosix::~PluginLoaderPosix() {
70 void PluginLoaderPosix::GetPluginsToLoad() {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
73 base::TimeTicks
start_time(base::TimeTicks::Now());
75 loaded_plugins_
.clear();
78 canonical_list_
.clear();
79 PluginList::Singleton()->GetPluginPathsToLoad(
81 PluginService::GetInstance()->NPAPIPluginsSupported());
83 internal_plugins_
.clear();
84 PluginList::Singleton()->GetInternalPlugins(&internal_plugins_
);
86 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
87 base::Bind(&PluginLoaderPosix::LoadPluginsInternal
,
88 make_scoped_refptr(this)));
90 HISTOGRAM_TIMES("PluginLoaderPosix.GetPluginList",
91 (base::TimeTicks::Now() - start_time
) *
92 base::Time::kMicrosecondsPerMillisecond
);
95 void PluginLoaderPosix::LoadPluginsInternal() {
96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
98 // Check if the list is empty or all plugins have already been loaded before
100 if (MaybeRunPendingCallbacks())
103 if (load_start_time_
.is_null())
104 load_start_time_
= base::TimeTicks::Now();
106 UtilityProcessHostImpl
* host
= new UtilityProcessHostImpl(
108 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
).get());
109 process_host_
= host
->AsWeakPtr();
110 process_host_
->DisableSandbox();
111 #if defined(OS_MACOSX)
112 host
->set_child_flags(ChildProcessHost::CHILD_ALLOW_HEAP_EXECUTION
);
115 process_host_
->Send(new UtilityMsg_LoadPlugins(canonical_list_
));
118 void PluginLoaderPosix::OnPluginLoaded(uint32 index
,
119 const WebPluginInfo
& plugin
) {
120 if (index
!= next_load_index_
) {
121 LOG(ERROR
) << "Received unexpected plugin load message for "
122 << plugin
.path
.value() << "; index=" << index
;
126 if (!MaybeAddInternalPlugin(plugin
.path
))
127 loaded_plugins_
.push_back(plugin
);
131 MaybeRunPendingCallbacks();
134 void PluginLoaderPosix::OnPluginLoadFailed(uint32 index
,
135 const base::FilePath
& plugin_path
) {
136 if (index
!= next_load_index_
) {
137 LOG(ERROR
) << "Received unexpected plugin load failure message for "
138 << plugin_path
.value() << "; index=" << index
;
144 MaybeAddInternalPlugin(plugin_path
);
145 MaybeRunPendingCallbacks();
148 bool PluginLoaderPosix::MaybeAddInternalPlugin(
149 const base::FilePath
& plugin_path
) {
150 for (std::vector
<WebPluginInfo
>::iterator it
= internal_plugins_
.begin();
151 it
!= internal_plugins_
.end();
153 if (it
->path
== plugin_path
) {
154 loaded_plugins_
.push_back(*it
);
155 internal_plugins_
.erase(it
);
162 bool PluginLoaderPosix::MaybeRunPendingCallbacks() {
163 if (next_load_index_
< canonical_list_
.size())
166 PluginList::Singleton()->SetPlugins(loaded_plugins_
);
168 // Only call the first callback with loaded plugins because there may be
169 // some extra plugin paths added since the first callback is added.
170 if (!callbacks_
.empty()) {
171 PendingCallback callback
= callbacks_
.front();
172 callbacks_
.pop_front();
173 callback
.target_loop
->PostTask(
175 base::Bind(callback
.callback
, loaded_plugins_
));
178 HISTOGRAM_TIMES("PluginLoaderPosix.LoadDone",
179 (base::TimeTicks::Now() - load_start_time_
)
180 * base::Time::kMicrosecondsPerMillisecond
);
181 load_start_time_
= base::TimeTicks();
183 if (!callbacks_
.empty()) {
184 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
185 base::Bind(&PluginLoaderPosix::GetPluginsToLoad
, this));
191 PluginLoaderPosix::PendingCallback::PendingCallback(
192 scoped_refptr
<base::MessageLoopProxy
> loop
,
193 const PluginService::GetPluginsCallback
& cb
)
198 PluginLoaderPosix::PendingCallback::~PendingCallback() {
201 } // namespace content