- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / plugin_loader_posix.cc
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/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
18 namespace content {
19
20 PluginLoaderPosix::PluginLoaderPosix()
21     : next_load_index_(0) {
22 }
23
24 void PluginLoaderPosix::LoadPlugins(
25     scoped_refptr<base::MessageLoopProxy> target_loop,
26     const PluginService::GetPluginsCallback& callback) {
27   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
28
29   callbacks_.push_back(PendingCallback(target_loop, callback));
30
31   if (callbacks_.size() == 1) {
32     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
33         base::Bind(&PluginLoaderPosix::GetPluginsToLoad, this));
34   }
35 }
36
37 bool PluginLoaderPosix::OnMessageReceived(const IPC::Message& message) {
38   bool handled = true;
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)
43   IPC_END_MESSAGE_MAP()
44   return handled;
45 }
46
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();
51   } else {
52     canonical_list_.erase(canonical_list_.begin(),
53                           canonical_list_.begin() + next_load_index_ + 1);
54   }
55
56   next_load_index_ = 0;
57
58   LoadPluginsInternal();
59 }
60
61 bool PluginLoaderPosix::Send(IPC::Message* message) {
62   if (process_host_.get())
63     return process_host_->Send(message);
64   return false;
65 }
66
67 PluginLoaderPosix::~PluginLoaderPosix() {
68 }
69
70 void PluginLoaderPosix::GetPluginsToLoad() {
71   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
72
73   base::TimeTicks start_time(base::TimeTicks::Now());
74
75   loaded_plugins_.clear();
76   next_load_index_ = 0;
77
78   canonical_list_.clear();
79   PluginList::Singleton()->GetPluginPathsToLoad(
80       &canonical_list_,
81       PluginService::GetInstance()->NPAPIPluginsSupported());
82
83   internal_plugins_.clear();
84   PluginList::Singleton()->GetInternalPlugins(&internal_plugins_);
85
86   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
87       base::Bind(&PluginLoaderPosix::LoadPluginsInternal,
88                  make_scoped_refptr(this)));
89
90   HISTOGRAM_TIMES("PluginLoaderPosix.GetPluginList",
91                   (base::TimeTicks::Now() - start_time) *
92                       base::Time::kMicrosecondsPerMillisecond);
93 }
94
95 void PluginLoaderPosix::LoadPluginsInternal() {
96   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
97
98   // Check if the list is empty or all plugins have already been loaded before
99   // forking.
100   if (MaybeRunPendingCallbacks())
101     return;
102
103   if (load_start_time_.is_null())
104     load_start_time_ = base::TimeTicks::Now();
105
106   UtilityProcessHostImpl* host = new UtilityProcessHostImpl(
107       this,
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);
113 #endif
114
115   process_host_->Send(new UtilityMsg_LoadPlugins(canonical_list_));
116 }
117
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;
123     return;
124   }
125
126   if (!MaybeAddInternalPlugin(plugin.path))
127     loaded_plugins_.push_back(plugin);
128
129   ++next_load_index_;
130
131   MaybeRunPendingCallbacks();
132 }
133
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;
139     return;
140   }
141
142   ++next_load_index_;
143
144   MaybeAddInternalPlugin(plugin_path);
145   MaybeRunPendingCallbacks();
146 }
147
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();
152        ++it) {
153     if (it->path == plugin_path) {
154       loaded_plugins_.push_back(*it);
155       internal_plugins_.erase(it);
156       return true;
157     }
158   }
159   return false;
160 }
161
162 bool PluginLoaderPosix::MaybeRunPendingCallbacks() {
163   if (next_load_index_ < canonical_list_.size())
164     return false;
165
166   PluginList::Singleton()->SetPlugins(loaded_plugins_);
167
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(
174         FROM_HERE,
175         base::Bind(callback.callback, loaded_plugins_));
176   }
177
178   HISTOGRAM_TIMES("PluginLoaderPosix.LoadDone",
179                   (base::TimeTicks::Now() - load_start_time_)
180                       * base::Time::kMicrosecondsPerMillisecond);
181   load_start_time_ = base::TimeTicks();
182
183   if (!callbacks_.empty()) {
184     BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
185         base::Bind(&PluginLoaderPosix::GetPluginsToLoad, this));
186     return false;
187   }
188   return true;
189 }
190
191 PluginLoaderPosix::PendingCallback::PendingCallback(
192     scoped_refptr<base::MessageLoopProxy> loop,
193     const PluginService::GetPluginsCallback& cb)
194     : target_loop(loop),
195       callback(cb) {
196 }
197
198 PluginLoaderPosix::PendingCallback::~PendingCallback() {
199 }
200
201 }  // namespace content