OLD | NEW |
| (Empty) |
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 "chrome_frame/cfproxy_private.h" | |
6 | |
7 #include <vector> | |
8 #include "base/atomic_sequence_num.h" | |
9 #include "base/command_line.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/process_util.h" | |
12 #include "chrome/common/automation_messages.h" | |
13 #include "chrome/common/chrome_switches.h" | |
14 #include "chrome_frame/chrome_launcher_utils.h" | |
15 #include "chrome_frame/utils.h" // for IsHeadlessMode(); | |
16 | |
17 | |
18 namespace { | |
19 void DispatchReplyFail(uint32 type, | |
20 ChromeProxyDelegate* delegate, | |
21 SyncMessageContext* ctx) { | |
22 switch (type) { | |
23 case AutomationMsg_CreateExternalTab::ID: | |
24 delegate->Completed_CreateTab(false, NULL, NULL, 0, 0); | |
25 break; | |
26 case AutomationMsg_ConnectExternalTab::ID: | |
27 delegate->Completed_ConnectToTab(false, NULL, NULL, 0, 0); | |
28 break; | |
29 } | |
30 } | |
31 | |
32 bool DispatchReplyOk(const IPC::Message* reply_msg, uint32 type, | |
33 ChromeProxyDelegate* delegate, SyncMessageContext* ctx, | |
34 TabsMap* tab2delegate) { | |
35 PickleIterator iter = IPC::SyncMessage::GetDataIterator(reply_msg); | |
36 switch (type) { | |
37 case AutomationMsg_CreateExternalTab::ID: { | |
38 // Tuple4<HWND, HWND, int, int> out; | |
39 TupleTypes<AutomationMsg_CreateExternalTab::ReplyParam>::ValueTuple out; | |
40 if (ReadParam(reply_msg, &iter, &out)) { | |
41 DCHECK(tab2delegate->find(out.c) == tab2delegate->end()); | |
42 (*tab2delegate)[out.c] = delegate; | |
43 delegate->Completed_CreateTab(true, out.a, out.b, out.c, out.d); | |
44 } | |
45 return true; | |
46 } | |
47 | |
48 case AutomationMsg_ConnectExternalTab::ID: { | |
49 // Tuple4<HWND, HWND, int, int> out; | |
50 TupleTypes<AutomationMsg_ConnectExternalTab::ReplyParam>::ValueTuple out; | |
51 if (ReadParam(reply_msg, &iter, &out)) { | |
52 DCHECK(tab2delegate->find(out.c) == tab2delegate->end()); | |
53 (*tab2delegate)[out.c] = delegate; | |
54 delegate->Completed_ConnectToTab(true, out.a, out.b, out.c, out.d); | |
55 } | |
56 return true; | |
57 } | |
58 } // switch | |
59 | |
60 return false; | |
61 } | |
62 } // namespace | |
63 | |
64 // Itf2IPCMessage | |
65 // Converts and sends trivial messages. | |
66 void Interface2IPCMessage::RemoveBrowsingData(int mask) { | |
67 sender_->Send(new AutomationMsg_RemoveBrowsingData(mask)); | |
68 } | |
69 | |
70 void Interface2IPCMessage::SetProxyConfig( | |
71 const std::string& json_encoded_proxy_cfg) { | |
72 sender_->Send(new AutomationMsg_SetProxyConfig(json_encoded_proxy_cfg)); | |
73 } | |
74 | |
75 // Tab related. | |
76 void Interface2IPCMessage::Tab_PostMessage(int tab, const std::string& message, | |
77 const std::string& origin, const std::string& target) { | |
78 sender_->Send(new AutomationMsg_HandleMessageFromExternalHost( | |
79 tab, message, origin, target)); | |
80 } | |
81 | |
82 void Interface2IPCMessage::Tab_Reload(int tab) { | |
83 sender_->Send(new AutomationMsg_ReloadAsync(tab)); | |
84 } | |
85 | |
86 void Interface2IPCMessage::Tab_Stop(int tab) { | |
87 sender_->Send(new AutomationMsg_StopAsync(tab)); | |
88 } | |
89 | |
90 void Interface2IPCMessage::Tab_SaveAs(int tab) { | |
91 sender_->Send(new AutomationMsg_SaveAsAsync(tab)); | |
92 } | |
93 | |
94 void Interface2IPCMessage::Tab_Print(int tab) { | |
95 sender_->Send(new AutomationMsg_PrintAsync(tab)); | |
96 } | |
97 | |
98 void Interface2IPCMessage::Tab_Cut(int tab) { | |
99 sender_->Send(new AutomationMsg_Cut(tab)); | |
100 } | |
101 | |
102 void Interface2IPCMessage::Tab_Copy(int tab) { | |
103 sender_->Send(new AutomationMsg_Copy(tab)); | |
104 } | |
105 | |
106 void Interface2IPCMessage::Tab_Paste(int tab) { | |
107 sender_->Send(new AutomationMsg_Paste(tab)); | |
108 } | |
109 | |
110 void Interface2IPCMessage::Tab_SelectAll(int tab) { | |
111 sender_->Send(new AutomationMsg_SelectAll(tab)); | |
112 } | |
113 | |
114 void Interface2IPCMessage::Tab_MenuCommand(int tab, int selected_command) { | |
115 sender_->Send(new AutomationMsg_ForwardContextMenuCommandToChrome( | |
116 tab, selected_command)); | |
117 } | |
118 | |
119 void Interface2IPCMessage::Tab_Zoom(int tab, content::PageZoom zoom_level) { | |
120 sender_->Send(new AutomationMsg_SetZoomLevel(tab, zoom_level)); | |
121 } | |
122 | |
123 void Interface2IPCMessage::Tab_FontSize(int tab, | |
124 enum AutomationPageFontSize font_size) { | |
125 sender_->Send(new AutomationMsg_SetPageFontSize(tab, font_size)); | |
126 } | |
127 | |
128 void Interface2IPCMessage::Tab_SetInitialFocus(int tab, bool reverse, | |
129 bool restore_focus_to_view) { | |
130 sender_->Send(new AutomationMsg_SetInitialFocus(tab, reverse, | |
131 restore_focus_to_view)); | |
132 } | |
133 | |
134 void Interface2IPCMessage::Tab_SetParentWindow(int tab) { | |
135 CHECK(0) << "Implement me"; | |
136 // AutomationMsg_TabReposition | |
137 } | |
138 | |
139 void Interface2IPCMessage::Tab_Resize(int tab) { | |
140 CHECK(0) << "Implement me"; | |
141 // AutomationMsg_TabReposition | |
142 } | |
143 | |
144 void Interface2IPCMessage::Tab_ProcessAccelerator(int tab, const MSG& msg) { | |
145 sender_->Send(new AutomationMsg_ProcessUnhandledAccelerator(tab, msg)); | |
146 } | |
147 | |
148 // Misc. | |
149 void Interface2IPCMessage::Tab_OnHostMoved(int tab) { | |
150 sender_->Send(new AutomationMsg_BrowserMove(tab)); | |
151 } | |
152 | |
153 void DelegateHolder::AddDelegate(ChromeProxyDelegate* p) { | |
154 delegate_list_.insert(p); | |
155 } | |
156 | |
157 void DelegateHolder::RemoveDelegate(ChromeProxyDelegate* p) { | |
158 // DCHECK(CalledOnValidThread()); | |
159 int tab_handle = p->tab_handle(); // Could be 0. | |
160 delegate_list_.erase(p); | |
161 tab2delegate_.erase(tab_handle); | |
162 } | |
163 | |
164 ChromeProxyDelegate* DelegateHolder::Tab2Delegate(int tab_handle) { | |
165 TabsMap::const_iterator iter = tab2delegate_.find(tab_handle); | |
166 if (iter != tab2delegate_.end()) | |
167 return iter->second; | |
168 return NULL; | |
169 } | |
170 | |
171 SyncMsgSender::SyncMsgSender(TabsMap* tab2delegate) | |
172 : tab2delegate_(tab2delegate) { | |
173 } | |
174 | |
175 // The outgoing queue of sync messages must be locked. | |
176 // Case: ui thread is sending message and waits for event, that is going to be | |
177 // signaled by completion handler in ipc_thread. | |
178 // We must append the message to the outgoing queue in UI thread, | |
179 // otherwise if channel is disconnected before having a chance to | |
180 // send the message, the ChromeProxyDelegate::_Disconnect implementation | |
181 // shall know how to unblock arbitrary sync call. Instead | |
182 // ChromeProxyDelgate::Completed_XXXX knows how to unblock a specific one. | |
183 void SyncMsgSender::QueueSyncMessage(const IPC::SyncMessage* msg, | |
184 ChromeProxyDelegate* delegate, | |
185 SyncMessageContext* ctx) { | |
186 if (delegate) { | |
187 // We are interested of the result. | |
188 base::AutoLock lock(messages_lock_); | |
189 int id = IPC::SyncMessage::GetMessageId(*msg); | |
190 // A message can be sent only once. | |
191 DCHECK(messages_.end() == messages_.find(id)); | |
192 messages_[id] = new SingleSentMessage(msg->type(), delegate, ctx); | |
193 } | |
194 } | |
195 | |
196 // Cancel all outgoing calls for this delegate. | |
197 void SyncMsgSender::Cancel(ChromeProxyDelegate* delegate) { | |
198 std::vector<SingleSentMessage*> cancelled; | |
199 { | |
200 base::AutoLock lock(messages_lock_); | |
201 SentMessages::iterator it = messages_.begin(); | |
202 for (; it != messages_.end(); ) { | |
203 SingleSentMessage* origin = it->second; | |
204 if (origin->delegate_ == delegate) { | |
205 cancelled.push_back(origin); | |
206 it = messages_.erase(it); | |
207 } else { | |
208 ++it; | |
209 } | |
210 } | |
211 } | |
212 | |
213 for (std::vector<SingleSentMessage*>::iterator it = cancelled.begin(); | |
214 it != cancelled.end(); ++it) { | |
215 SingleSentMessage* origin = *it; | |
216 DispatchReplyFail(origin->type_, delegate, origin->ctx_); | |
217 delete origin; | |
218 } | |
219 } | |
220 | |
221 SyncMsgSender::SingleSentMessage* SyncMsgSender::RemoveMessage(int id) { | |
222 base::AutoLock lock(messages_lock_); | |
223 SentMessages::iterator it = messages_.find(id); | |
224 if (it == messages_.end()) { | |
225 // Delegate is not interested in this sync message response. | |
226 return NULL; | |
227 } | |
228 | |
229 // See what message is this. | |
230 SingleSentMessage* origin = it->second; | |
231 messages_.erase(it); | |
232 return origin; | |
233 } | |
234 | |
235 bool SyncMsgSender::OnReplyReceived(const IPC::Message* reply_msg) { | |
236 if (!reply_msg->is_reply()) | |
237 return false; // Not a reply to sync message. | |
238 | |
239 // Find message by id. | |
240 int id = IPC::SyncMessage::GetMessageId(*reply_msg); | |
241 SingleSentMessage* origin = RemoveMessage(id); | |
242 if (origin) { | |
243 DispatchReplyOk(reply_msg, origin->type_, origin->delegate_, origin->ctx_, | |
244 tab2delegate_); | |
245 delete origin; | |
246 } | |
247 | |
248 return true; | |
249 } | |
250 | |
251 void SyncMsgSender::OnChannelClosed() { | |
252 SentMessages messages_sent; | |
253 // Make a copy of the messages queue | |
254 { | |
255 base::AutoLock lock(messages_lock_); | |
256 messages_.swap(messages_sent); | |
257 } | |
258 | |
259 | |
260 SentMessages::reverse_iterator it = messages_sent.rbegin(); | |
261 for (; it != messages_sent.rend(); ++it) { | |
262 SingleSentMessage* origin = it->second; | |
263 DispatchReplyFail(origin->type_, origin->delegate_, origin->ctx_); | |
264 delete origin; | |
265 } | |
266 messages_sent.clear(); | |
267 } | |
268 | |
269 static base::StaticAtomicSequenceNumber g_proxy_channel_id; | |
270 std::string GenerateChannelId() { | |
271 return StringPrintf("ChromeTestingInterface:%u.%d", | |
272 base::GetCurrentProcId(), g_proxy_channel_id.GetNext() + 0xC000); | |
273 } | |
274 | |
275 std::wstring BuildCmdLine(const std::string& channel_id, | |
276 const FilePath& profile_path, | |
277 const std::wstring& extra_args) { | |
278 std::wstring command_line_string; | |
279 scoped_ptr<CommandLine> command_line; | |
280 if (chrome_launcher::CreateLaunchCommandLine(&command_line)) { | |
281 command_line->AppendSwitchASCII(switches::kAutomationClientChannelID, | |
282 channel_id); | |
283 // Run Chrome in Chrome Frame mode. In practice, this modifies the paths | |
284 // and registry keys that Chrome looks in via the BrowserDistribution | |
285 // mechanism. | |
286 command_line->AppendSwitch(switches::kChromeFrame); | |
287 // Chrome Frame never wants Chrome to start up with a First Run UI. | |
288 command_line->AppendSwitch(switches::kNoFirstRun); | |
289 command_line->AppendSwitch(switches::kDisablePopupBlocking); | |
290 | |
291 #ifndef NDEBUG | |
292 // Disable the "Whoa! Chrome has crashed." dialog, because that isn't very | |
293 // useful for Chrome Frame users. | |
294 command_line->AppendSwitch(switches::kNoErrorDialogs); | |
295 #endif | |
296 | |
297 // In headless mode runs like reliability test runs we want full crash dumps | |
298 // from chrome. | |
299 if (IsHeadlessMode()) | |
300 command_line->AppendSwitch(switches::kFullMemoryCrashReport); | |
301 | |
302 command_line->AppendSwitchPath(switches::kUserDataDir, profile_path); | |
303 | |
304 command_line_string = command_line->GetCommandLineString(); | |
305 if (!extra_args.empty()) { | |
306 command_line_string.append(L" "); | |
307 command_line_string.append(extra_args); | |
308 } | |
309 } | |
310 | |
311 return command_line_string; | |
312 } | |
OLD | NEW |