1 // Copyright (c) 2011 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 "chrome_frame/cfproxy_private.h"
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();
19 void DispatchReplyFail(uint32 type
,
20 ChromeProxyDelegate
* delegate
,
21 SyncMessageContext
* ctx
) {
23 case AutomationMsg_CreateExternalTab::ID
:
24 delegate
->Completed_CreateTab(false, NULL
, NULL
, 0, 0);
26 case AutomationMsg_ConnectExternalTab::ID
:
27 delegate
->Completed_ConnectToTab(false, NULL
, NULL
, 0, 0);
32 bool DispatchReplyOk(const IPC::Message
* reply_msg
, uint32 type
,
33 ChromeProxyDelegate
* delegate
, SyncMessageContext
* ctx
,
34 TabsMap
* tab2delegate
) {
35 void* iter
= IPC::SyncMessage::GetDataIterator(reply_msg
);
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
);
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
);
65 // Converts and sends trivial messages.
66 void Interface2IPCMessage::RemoveBrowsingData(int mask
) {
67 sender_
->Send(new AutomationMsg_RemoveBrowsingData(mask
));
70 void Interface2IPCMessage::SetProxyConfig(
71 const std::string
& json_encoded_proxy_cfg
) {
72 sender_
->Send(new AutomationMsg_SetProxyConfig(json_encoded_proxy_cfg
));
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
));
82 void Interface2IPCMessage::Tab_Reload(int tab
) {
83 sender_
->Send(new AutomationMsg_ReloadAsync(tab
));
86 void Interface2IPCMessage::Tab_Stop(int tab
) {
87 sender_
->Send(new AutomationMsg_StopAsync(tab
));
90 void Interface2IPCMessage::Tab_SaveAs(int tab
) {
91 sender_
->Send(new AutomationMsg_SaveAsAsync(tab
));
94 void Interface2IPCMessage::Tab_Print(int tab
) {
95 sender_
->Send(new AutomationMsg_PrintAsync(tab
));
98 void Interface2IPCMessage::Tab_Cut(int tab
) {
99 sender_
->Send(new AutomationMsg_Cut(tab
));
102 void Interface2IPCMessage::Tab_Copy(int tab
) {
103 sender_
->Send(new AutomationMsg_Copy(tab
));
106 void Interface2IPCMessage::Tab_Paste(int tab
) {
107 sender_
->Send(new AutomationMsg_Paste(tab
));
110 void Interface2IPCMessage::Tab_SelectAll(int tab
) {
111 sender_
->Send(new AutomationMsg_SelectAll(tab
));
114 void Interface2IPCMessage::Tab_MenuCommand(int tab
, int selected_command
) {
115 sender_
->Send(new AutomationMsg_ForwardContextMenuCommandToChrome(
116 tab
, selected_command
));
119 void Interface2IPCMessage::Tab_Zoom(int tab
, PageZoom::Function zoom_level
) {
120 sender_
->Send(new AutomationMsg_SetZoomLevel(tab
, zoom_level
));
123 void Interface2IPCMessage::Tab_FontSize(int tab
,
124 enum AutomationPageFontSize font_size
) {
125 sender_
->Send(new AutomationMsg_SetPageFontSize(tab
, font_size
));
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
));
134 void Interface2IPCMessage::Tab_SetParentWindow(int tab
) {
135 CHECK(0) << "Implement me";
136 // AutomationMsg_TabReposition
139 void Interface2IPCMessage::Tab_Resize(int tab
) {
140 CHECK(0) << "Implement me";
141 // AutomationMsg_TabReposition
144 void Interface2IPCMessage::Tab_ProcessAccelerator(int tab
, const MSG
& msg
) {
145 sender_
->Send(new AutomationMsg_ProcessUnhandledAccelerator(tab
, msg
));
149 void Interface2IPCMessage::Tab_OnHostMoved(int tab
) {
150 sender_
->Send(new AutomationMsg_BrowserMove(tab
));
153 void DelegateHolder::AddDelegate(ChromeProxyDelegate
* p
) {
154 delegate_list_
.insert(p
);
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
);
164 ChromeProxyDelegate
* DelegateHolder::Tab2Delegate(int tab_handle
) {
165 TabsMap::const_iterator iter
= tab2delegate_
.find(tab_handle
);
166 if (iter
!= tab2delegate_
.end())
171 SyncMsgSender::SyncMsgSender(TabsMap
* tab2delegate
)
172 : tab2delegate_(tab2delegate
) {
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
) {
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
);
196 // Cancel all outgoing calls for this delegate.
197 void SyncMsgSender::Cancel(ChromeProxyDelegate
* delegate
) {
198 std::vector
<SingleSentMessage
*> cancelled
;
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
);
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_
);
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.
229 // See what message is this.
230 SingleSentMessage
* origin
= it
->second
;
235 bool SyncMsgSender::OnReplyReceived(const IPC::Message
* reply_msg
) {
236 if (!reply_msg
->is_reply())
237 return false; // Not a reply to sync message.
239 // Find message by id.
240 int id
= IPC::SyncMessage::GetMessageId(*reply_msg
);
241 SingleSentMessage
* origin
= RemoveMessage(id
);
243 DispatchReplyOk(reply_msg
, origin
->type_
, origin
->delegate_
, origin
->ctx_
,
251 void SyncMsgSender::OnChannelClosed() {
252 SentMessages messages_sent
;
253 // Make a copy of the messages queue
255 base::AutoLock
lock(messages_lock_
);
256 messages_
.swap(messages_sent
);
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_
);
266 messages_sent
.clear();
269 static base::AtomicSequenceNumber
g_proxy_channel_id(base::LINKER_INITIALIZED
);
270 std::string
GenerateChannelId() {
271 return StringPrintf("ChromeTestingInterface:%u.%d",
272 base::GetCurrentProcId(), g_proxy_channel_id
.GetNext() + 0xC000);
275 std::wstring
BuildCmdLine(const std::string
& channel_id
,
276 const FilePath
& profile_path
,
277 const std::wstring
& extra_args
) {
278 scoped_ptr
<CommandLine
> command_line(
279 chrome_launcher::CreateLaunchCommandLine());
280 command_line
->AppendSwitchASCII(switches::kAutomationClientChannelID
,
282 // Run Chrome in Chrome Frame mode. In practice, this modifies the paths
283 // and registry keys that Chrome looks in via the BrowserDistribution
285 command_line
->AppendSwitch(switches::kChromeFrame
);
286 // Chrome Frame never wants Chrome to start up with a First Run UI.
287 command_line
->AppendSwitch(switches::kNoFirstRun
);
288 command_line
->AppendSwitch(switches::kDisablePopupBlocking
);
291 // Disable the "Whoa! Chrome has crashed." dialog, because that isn't very
292 // useful for Chrome Frame users.
293 command_line
->AppendSwitch(switches::kNoErrorDialogs
);
296 // In headless mode runs like reliability test runs we want full crash dumps
298 if (IsHeadlessMode())
299 command_line
->AppendSwitch(switches::kFullMemoryCrashReport
);
301 command_line
->AppendSwitchPath(switches::kUserDataDir
, profile_path
);
303 std::wstring
command_line_string(command_line
->GetCommandLineString());
304 if (!extra_args
.empty()) {
305 command_line_string
.append(L
" ");
306 command_line_string
.append(extra_args
);
308 return command_line_string
;