| 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 |