|
1 /* |
|
2 * Copyright (C) 2010 Apple Inc. All rights reserved. |
|
3 * |
|
4 * Redistribution and use in source and binary forms, with or without |
|
5 * modification, are permitted provided that the following conditions |
|
6 * are met: |
|
7 * 1. Redistributions of source code must retain the above copyright |
|
8 * notice, this list of conditions and the following disclaimer. |
|
9 * 2. Redistributions in binary form must reproduce the above copyright |
|
10 * notice, this list of conditions and the following disclaimer in the |
|
11 * documentation and/or other materials provided with the distribution. |
|
12 * |
|
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
|
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
|
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
23 * THE POSSIBILITY OF SUCH DAMAGE. |
|
24 */ |
|
25 |
|
26 #include "WebProcessProxy.h" |
|
27 |
|
28 #include "PluginInfoStore.h" |
|
29 #include "ProcessLauncher.h" |
|
30 #include "WebBackForwardListItem.h" |
|
31 #include "WebContext.h" |
|
32 #include "WebPageNamespace.h" |
|
33 #include "WebPageProxy.h" |
|
34 #include "WebProcessManager.h" |
|
35 #include "WebProcessMessageKinds.h" |
|
36 #include "WebProcessProxyMessageKinds.h" |
|
37 #include <WebCore/KURL.h> |
|
38 #include <WebCore/PlatformString.h> |
|
39 #include <wtf/text/CString.h> |
|
40 |
|
41 #if ENABLE(WEB_PROCESS_SANDBOX) |
|
42 #include <sandbox.h> |
|
43 #endif |
|
44 |
|
45 using namespace WebCore; |
|
46 |
|
47 namespace WebKit { |
|
48 |
|
49 static uint64_t generatePageID() |
|
50 { |
|
51 static uint64_t uniquePageID = 1; |
|
52 return uniquePageID++; |
|
53 } |
|
54 |
|
55 PassRefPtr<WebProcessProxy> WebProcessProxy::create(WebContext* context) |
|
56 { |
|
57 return adoptRef(new WebProcessProxy(context)); |
|
58 } |
|
59 |
|
60 WebProcessProxy::WebProcessProxy(WebContext* context) |
|
61 : m_responsivenessTimer(this) |
|
62 , m_context(context) |
|
63 { |
|
64 connect(); |
|
65 |
|
66 // FIXME: Instead of sending three separate initialization related messages here, we should just send a |
|
67 // single "Initialize" messages with a struct that has all the needed information. |
|
68 send(WebProcessMessage::SetApplicationCacheDirectory, 0, CoreIPC::In(m_context->applicationCacheDirectory())); |
|
69 |
|
70 // FIXME: We could instead send the bundle path as part of the arguments to process creation? |
|
71 // Would that be better than sending a connection? |
|
72 if (!context->injectedBundlePath().isEmpty()) { |
|
73 #if ENABLE(WEB_PROCESS_SANDBOX) |
|
74 char *sandboxBundleToken = NULL; |
|
75 CString injectedBundlePath = context->injectedBundlePath().utf8(); |
|
76 sandbox_issue_extension(injectedBundlePath.data(), &sandboxBundleToken); |
|
77 send(WebProcessMessage::LoadInjectedBundle, 0, CoreIPC::In(context->injectedBundlePath(), String::fromUTF8(sandboxBundleToken))); |
|
78 if (sandboxBundleToken) |
|
79 free(sandboxBundleToken); |
|
80 #else |
|
81 send(WebProcessMessage::LoadInjectedBundle, 0, CoreIPC::In(context->injectedBundlePath())); |
|
82 #endif |
|
83 } |
|
84 |
|
85 #if USE(ACCELERATED_COMPOSITING) |
|
86 setUpAcceleratedCompositing(); |
|
87 #endif |
|
88 |
|
89 } |
|
90 |
|
91 WebProcessProxy::~WebProcessProxy() |
|
92 { |
|
93 ASSERT(!m_connection); |
|
94 |
|
95 for (size_t i = 0; i < m_pendingMessages.size(); ++i) |
|
96 m_pendingMessages[i].destroy(); |
|
97 |
|
98 if (m_processLauncher) { |
|
99 m_processLauncher->invalidate(); |
|
100 m_processLauncher = 0; |
|
101 } |
|
102 } |
|
103 |
|
104 void WebProcessProxy::connect() |
|
105 { |
|
106 if (m_context->processModel() == ProcessModelSharedSecondaryThread) { |
|
107 CoreIPC::Connection::Identifier connectionIdentifier = ProcessLauncher::createWebThread(); |
|
108 didFinishLaunching(0, connectionIdentifier); |
|
109 return; |
|
110 } |
|
111 |
|
112 ASSERT(!m_processLauncher); |
|
113 m_processLauncher = ProcessLauncher::create(this); |
|
114 } |
|
115 |
|
116 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments) |
|
117 { |
|
118 // If we're waiting for the web process to launch, we need to stash away the messages so we can send them once we have |
|
119 // a CoreIPC connection. |
|
120 if (isLaunching()) { |
|
121 m_pendingMessages.append(CoreIPC::Connection::OutgoingMessage(messageID, arguments)); |
|
122 return true; |
|
123 } |
|
124 |
|
125 return m_connection->sendMessage(messageID, arguments); |
|
126 } |
|
127 |
|
128 void WebProcessProxy::terminate() |
|
129 { |
|
130 if (m_processLauncher) |
|
131 m_processLauncher->terminateProcess(); |
|
132 } |
|
133 |
|
134 #if USE(ACCELERATED_COMPOSITING) && !PLATFORM(MAC) |
|
135 void WebProcessProxy::setUpAcceleratedCompositing() |
|
136 { |
|
137 } |
|
138 #endif |
|
139 |
|
140 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const |
|
141 { |
|
142 return m_pageMap.get(pageID).get(); |
|
143 } |
|
144 |
|
145 WebPageProxy* WebProcessProxy::createWebPage(WebPageNamespace* pageNamespace) |
|
146 { |
|
147 ASSERT(pageNamespace->process() == this); |
|
148 |
|
149 unsigned pageID = generatePageID(); |
|
150 RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageNamespace, pageID); |
|
151 m_pageMap.set(pageID, webPage); |
|
152 return webPage.get(); |
|
153 } |
|
154 |
|
155 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID) |
|
156 { |
|
157 m_pageMap.set(pageID, webPage); |
|
158 } |
|
159 |
|
160 void WebProcessProxy::removeWebPage(uint64_t pageID) |
|
161 { |
|
162 m_pageMap.remove(pageID); |
|
163 } |
|
164 |
|
165 WebProcessProxy::pages_const_iterator WebProcessProxy::pages_begin() |
|
166 { |
|
167 return m_pageMap.begin().values(); |
|
168 } |
|
169 |
|
170 WebProcessProxy::pages_const_iterator WebProcessProxy::pages_end() |
|
171 { |
|
172 return m_pageMap.end().values(); |
|
173 } |
|
174 |
|
175 size_t WebProcessProxy::numberOfPages() |
|
176 { |
|
177 return m_pageMap.size(); |
|
178 } |
|
179 |
|
180 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const |
|
181 { |
|
182 return m_backForwardListItemMap.get(itemID).get(); |
|
183 } |
|
184 |
|
185 void WebProcessProxy::forwardMessageToWebContext(const String& message) |
|
186 { |
|
187 m_context->didRecieveMessageFromInjectedBundle(message); |
|
188 } |
|
189 |
|
190 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins) |
|
191 { |
|
192 if (refresh) |
|
193 m_context->pluginInfoStore()->refresh(); |
|
194 m_context->pluginInfoStore()->getPlugins(plugins); |
|
195 } |
|
196 |
|
197 void WebProcessProxy::getPluginHostConnection(const String& mimeType, const KURL& url, WebCore::String& pluginPath) |
|
198 { |
|
199 String newMimeType = mimeType.lower(); |
|
200 |
|
201 PluginInfoStore::Plugin plugin = m_context->pluginInfoStore()->findPlugin(newMimeType, url); |
|
202 if (!plugin.path) |
|
203 return; |
|
204 |
|
205 pluginPath = plugin.path; |
|
206 } |
|
207 |
|
208 void WebProcessProxy::addOrUpdateBackForwardListItem(uint64_t itemID, const String& originalURL, const String& url, const String& title) |
|
209 { |
|
210 std::pair<WebBackForwardListItemMap::iterator, bool> result = m_backForwardListItemMap.add(itemID, 0); |
|
211 if (result.second) { |
|
212 // New item. |
|
213 result.first->second = WebBackForwardListItem::create(originalURL, url, title, itemID); |
|
214 return; |
|
215 } |
|
216 |
|
217 // Update existing item. |
|
218 result.first->second->setOriginalURL(originalURL); |
|
219 result.first->second->setURL(url); |
|
220 result.first->second->setTitle(title); |
|
221 } |
|
222 |
|
223 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) |
|
224 { |
|
225 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) { |
|
226 switch (messageID.get<WebProcessProxyMessage::Kind>()) { |
|
227 case WebProcessProxyMessage::PostMessage: { |
|
228 String message; |
|
229 if (!arguments->decode(CoreIPC::Out(message))) |
|
230 return; |
|
231 |
|
232 forwardMessageToWebContext(message); |
|
233 return; |
|
234 } |
|
235 case WebProcessProxyMessage::AddBackForwardItem: { |
|
236 uint64_t itemID; |
|
237 String originalURL; |
|
238 String url; |
|
239 String title; |
|
240 if (!arguments->decode(CoreIPC::Out(itemID, originalURL, url, title))) |
|
241 return; |
|
242 addOrUpdateBackForwardListItem(itemID, originalURL, url, title); |
|
243 return; |
|
244 } |
|
245 |
|
246 // These are synchronous messages and should never be handled here. |
|
247 case WebProcessProxyMessage::GetPlugins: |
|
248 case WebProcessProxyMessage::GetPluginHostConnection: |
|
249 ASSERT_NOT_REACHED(); |
|
250 break; |
|
251 } |
|
252 } |
|
253 |
|
254 uint64_t pageID = arguments->destinationID(); |
|
255 if (!pageID) |
|
256 return; |
|
257 |
|
258 WebPageProxy* pageProxy = webPage(pageID); |
|
259 if (!pageProxy) |
|
260 return; |
|
261 |
|
262 pageProxy->didReceiveMessage(connection, messageID, *arguments); |
|
263 } |
|
264 |
|
265 void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply) |
|
266 { |
|
267 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) { |
|
268 switch (messageID.get<WebProcessProxyMessage::Kind>()) { |
|
269 case WebProcessProxyMessage::GetPlugins: { |
|
270 bool refresh; |
|
271 if (!arguments->decode(refresh)) |
|
272 return; |
|
273 |
|
274 // FIXME: We should not do this on the main thread! |
|
275 Vector<PluginInfo> plugins; |
|
276 getPlugins(refresh, plugins); |
|
277 |
|
278 reply->encode(plugins); |
|
279 break; |
|
280 } |
|
281 |
|
282 case WebProcessProxyMessage::GetPluginHostConnection: { |
|
283 #if PLATFORM(MAC) |
|
284 String mimeType; |
|
285 String urlString; |
|
286 |
|
287 if (!arguments->decode(CoreIPC::Out(mimeType, urlString))) |
|
288 return; |
|
289 |
|
290 String pluginPath; |
|
291 getPluginHostConnection(mimeType, KURL(ParsedURLString, urlString), pluginPath); |
|
292 reply->encode(CoreIPC::In(pluginPath)); |
|
293 #endif |
|
294 break; |
|
295 } |
|
296 |
|
297 // These are asynchronous messages and should never be handled here. |
|
298 case WebProcessProxyMessage::PostMessage: |
|
299 case WebProcessProxyMessage::AddBackForwardItem: |
|
300 ASSERT_NOT_REACHED(); |
|
301 break; |
|
302 } |
|
303 } |
|
304 |
|
305 uint64_t pageID = arguments->destinationID(); |
|
306 if (!pageID) |
|
307 return; |
|
308 |
|
309 WebPageProxy* pageProxy = webPage(pageID); |
|
310 if (!pageProxy) |
|
311 return; |
|
312 |
|
313 pageProxy->didReceiveSyncMessage(connection, messageID, *arguments, *reply); |
|
314 } |
|
315 |
|
316 void WebProcessProxy::didClose(CoreIPC::Connection*) |
|
317 { |
|
318 m_connection = 0; |
|
319 m_responsivenessTimer.stop(); |
|
320 |
|
321 Vector<RefPtr<WebPageProxy> > pages; |
|
322 copyValuesToVector(m_pageMap, pages); |
|
323 |
|
324 for (size_t i = 0, size = pages.size(); i < size; ++i) |
|
325 pages[i]->processDidExit(); |
|
326 |
|
327 // This may cause us to be deleted. |
|
328 WebProcessManager::shared().processDidClose(this, m_context); |
|
329 } |
|
330 |
|
331 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*) |
|
332 { |
|
333 Vector<RefPtr<WebPageProxy> > pages; |
|
334 copyValuesToVector(m_pageMap, pages); |
|
335 for (size_t i = 0, size = pages.size(); i < size; ++i) |
|
336 pages[i]->processDidBecomeUnresponsive(); |
|
337 } |
|
338 |
|
339 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*) |
|
340 { |
|
341 Vector<RefPtr<WebPageProxy> > pages; |
|
342 copyValuesToVector(m_pageMap, pages); |
|
343 for (size_t i = 0, size = pages.size(); i < size; ++i) |
|
344 pages[i]->processDidBecomeResponsive(); |
|
345 } |
|
346 |
|
347 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, const CoreIPC::Connection::Identifier& connectionIdentifier) |
|
348 { |
|
349 ASSERT(!m_connection); |
|
350 |
|
351 m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main()); |
|
352 m_connection->open(); |
|
353 |
|
354 for (size_t i = 0; i < m_pendingMessages.size(); ++i) { |
|
355 CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i]; |
|
356 m_connection->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments())); |
|
357 } |
|
358 |
|
359 m_pendingMessages.clear(); |
|
360 } |
|
361 |
|
362 } // namespace WebKit |