[email protected] | 7419d4b | 2011-04-06 15:18:04 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 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 "base/tuple.h" |
| 8 | #include "ipc/ipc_sync_message.h" |
[email protected] | a8ba636 | 2010-11-10 20:02:25 | [diff] [blame] | 9 | #include "chrome/common/automation_messages.h" |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 10 | |
| 11 | CFProxy::CFProxy(CFProxyTraits* api) : ipc_thread_("ipc"), |
| 12 | sync_dispatcher_(&tab2delegate_), |
| 13 | ipc_sender_(NULL), |
| 14 | api_(api), |
| 15 | delegate_count_(0), |
| 16 | is_connected_(false) { |
| 17 | } |
| 18 | |
| 19 | CFProxy::~CFProxy() { |
| 20 | ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 21 | &CFProxy::CleanupOnIoThread)); |
| 22 | // ipc_thread destructor will do the Stop anyway. this is for debug :) |
| 23 | ipc_thread_.Stop(); |
| 24 | } |
| 25 | |
| 26 | |
| 27 | void CFProxy::Init(const ProxyParams& params) { |
| 28 | ipc_thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0)); |
| 29 | ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 30 | &CFProxy::InitInIoThread, params)); |
| 31 | } |
| 32 | |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 33 | int CFProxy::AddDelegate(ChromeProxyDelegate* delegate) { |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 34 | ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 35 | &CFProxy::AddDelegateOnIoThread, delegate)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 36 | return ++delegate_count_; |
| 37 | } |
| 38 | |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 39 | int CFProxy::RemoveDelegate(ChromeProxyDelegate* delegate) { |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 40 | ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 41 | &CFProxy::RemoveDelegateOnIoThread, delegate)); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 42 | return --delegate_count_; |
| 43 | } |
| 44 | |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 45 | void CFProxy::AddDelegateOnIoThread(ChromeProxyDelegate* delegate) { |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 46 | DCHECK(CalledOnIpcThread()); |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 47 | DelegateHolder::AddDelegate(delegate); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 48 | if (is_connected_) { |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 49 | delegate->Connected(this); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 50 | } |
| 51 | } |
| 52 | |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 53 | void CFProxy::RemoveDelegateOnIoThread(ChromeProxyDelegate* delegate) { |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 54 | DCHECK(CalledOnIpcThread()); |
[email protected] | 314a0696 | 2010-10-20 21:32:32 | [diff] [blame] | 55 | // Cancel any calls in progress. |
| 56 | sync_dispatcher_.Cancel(delegate); |
| 57 | DelegateHolder::RemoveDelegate(delegate); |
| 58 | delegate->Disconnected(); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | void CFProxy::InitInIoThread(const ProxyParams& params) { |
| 62 | DCHECK(CalledOnIpcThread()); |
| 63 | std::string channel_id = GenerateChannelId(); |
| 64 | ipc_sender_ = api_->CreateChannel(channel_id, this); |
| 65 | std::wstring cmd_line = BuildCmdLine(channel_id, params.profile_path, |
| 66 | params.extra_params); |
| 67 | if (api_->LaunchApp(cmd_line)) { |
| 68 | CancelableTask* launch_timeout = NewRunnableMethod(this, |
| 69 | &CFProxy::LaunchTimeOut); |
| 70 | ipc_thread_.message_loop()->PostDelayedTask(FROM_HERE, launch_timeout, |
| 71 | params.timeout.InMilliseconds()); |
| 72 | } else { |
| 73 | OnPeerLost(ChromeProxyDelegate::CHROME_EXE_LAUNCH_FAILED); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | void CFProxy::CleanupOnIoThread() { |
| 78 | DCHECK(CalledOnIpcThread()); |
| 79 | if (ipc_sender_) { |
| 80 | api_->CloseChannel(ipc_sender_); |
| 81 | ipc_sender_ = NULL; |
| 82 | } |
| 83 | // TODO(stoyan): shall we notify delegates? |
| 84 | // The object is dying, so under normal circumstances there should be |
| 85 | // no delegates. |
| 86 | DCHECK_EQ(0, delegate_count_); |
| 87 | DCHECK_EQ(0u, delegate_list_.size()); |
| 88 | DCHECK_EQ(0u, tab2delegate_.size()); |
| 89 | } |
| 90 | |
| 91 | void CFProxy::LaunchTimeOut() { |
| 92 | DCHECK(CalledOnIpcThread()); |
| 93 | if (!is_connected_) { |
| 94 | OnPeerLost(ChromeProxyDelegate::CHROME_EXE_LAUNCH_TIMEOUT); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | void CFProxy::OnPeerLost(ChromeProxyDelegate::DisconnectReason reason) { |
| 99 | // Kill the channel. Inform delegates |
| 100 | DCHECK(CalledOnIpcThread()); |
| 101 | if (ipc_sender_) { |
| 102 | api_->CloseChannel(ipc_sender_); |
| 103 | ipc_sender_ = NULL; |
| 104 | } |
| 105 | |
| 106 | for (DelegateList::iterator it = delegate_list_.begin(); |
| 107 | it != delegate_list_.end(); ++it) { |
| 108 | (*it)->PeerLost(this, reason); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | void CFProxy::SendIpcMessage(IPC::Message* m) { |
| 113 | ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 114 | &CFProxy::SendIpcMessageOnIoThread, m)); |
| 115 | } |
| 116 | |
| 117 | void CFProxy::SendIpcMessageOnIoThread(IPC::Message* m) { |
| 118 | DCHECK(CalledOnIpcThread()); |
| 119 | if (ipc_sender_) { |
| 120 | ipc_sender_->Send(m); |
| 121 | } else { |
| 122 | delete m; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | ////////////////////////////////////////////////////////////////////////// |
| 127 | // Sync messages. |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 128 | void CFProxy::Tab_Find(int tab, const string16& search_string, |
| 129 | FindInPageDirection forward, FindInPageCase match_case, |
| 130 | bool find_next) { |
| 131 | AutomationMsg_Find_Params params; |
| 132 | params.unused = 0; |
| 133 | params.search_string = search_string; |
| 134 | params.find_next = find_next; |
| 135 | params.match_case = (match_case == CASE_SENSITIVE); |
| 136 | params.forward = (forward == FWD); |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 137 | IPC::SyncMessage* m = new AutomationMsg_Find(tab, params, NULL, NULL); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 138 | // Not interested in result. |
| 139 | sync_dispatcher_.QueueSyncMessage(m, NULL, NULL); |
| 140 | SendIpcMessage(m); |
| 141 | } |
| 142 | |
| 143 | void CFProxy::Tab_OverrideEncoding(int tab, const char* encoding) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 144 | IPC::SyncMessage* m = new AutomationMsg_OverrideEncoding(tab, encoding, NULL); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 145 | // Not interested in result. |
| 146 | sync_dispatcher_.QueueSyncMessage(m, NULL, NULL); |
| 147 | SendIpcMessage(m); |
| 148 | } |
| 149 | |
| 150 | void CFProxy::Tab_Navigate(int tab, const GURL& url, const GURL& referrer) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 151 | IPC::SyncMessage* m = new AutomationMsg_NavigateInExternalTab( |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 152 | tab, url, referrer, NULL); |
| 153 | // We probably are not interested in result since provider just checks |
| 154 | // whether tab handle is valid. |
| 155 | sync_dispatcher_.QueueSyncMessage(m, NULL, NULL); |
| 156 | SendIpcMessage(m); |
| 157 | } |
| 158 | |
| 159 | void CFProxy::CreateTab(ChromeProxyDelegate* delegate, |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 160 | const ExternalTabSettings& p) { |
| 161 | IPC::SyncMessage* m = new AutomationMsg_CreateExternalTab(p, 0, 0, 0, 0); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 162 | sync_dispatcher_.QueueSyncMessage(m, delegate, NULL); |
| 163 | SendIpcMessage(m); |
| 164 | } |
| 165 | |
| 166 | void CFProxy::ConnectTab(ChromeProxyDelegate* delegate, HWND hwnd, |
| 167 | uint64 cookie) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 168 | IPC::SyncMessage* m = new AutomationMsg_ConnectExternalTab(cookie, true, |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 169 | hwnd, NULL, NULL, NULL, 0); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 170 | sync_dispatcher_.QueueSyncMessage(m, delegate, NULL); |
| 171 | SendIpcMessage(m); |
| 172 | } |
| 173 | |
| 174 | void CFProxy::BlockTab(uint64 cookie) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 175 | IPC::SyncMessage* m = new AutomationMsg_ConnectExternalTab(cookie, false, |
[email protected] | 751bf4b | 2010-11-05 22:06:31 | [diff] [blame] | 176 | NULL, NULL, NULL, NULL, 0); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 177 | sync_dispatcher_.QueueSyncMessage(m, NULL, NULL); |
| 178 | SendIpcMessage(m); |
| 179 | } |
| 180 | |
| 181 | void CFProxy::Tab_RunUnloadHandlers(int tab) { |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 182 | IPC::SyncMessage* m = new AutomationMsg_RunUnloadHandlers(tab, 0); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 183 | ChromeProxyDelegate* p = Tab2Delegate(tab); |
| 184 | sync_dispatcher_.QueueSyncMessage(m, p, NULL); |
| 185 | SendIpcMessage(m); |
| 186 | } |
| 187 | |
| 188 | // IPC::Channel::Listener |
[email protected] | a95986a8 | 2010-12-24 06:19:28 | [diff] [blame] | 189 | bool CFProxy::OnMessageReceived(const IPC::Message& message) { |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 190 | // Handle sync message reply. |
| 191 | bool done = sync_dispatcher_.OnReplyReceived(&message); |
| 192 | if (done) |
[email protected] | a95986a8 | 2010-12-24 06:19:28 | [diff] [blame] | 193 | return true; |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 194 | |
| 195 | // Handle tab related message. |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 196 | ChromeProxyDelegate* d = Tab2Delegate(message.routing_id()); |
| 197 | if (d) |
| 198 | return d->OnMessageReceived(message); |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 199 | |
| 200 | DLOG(WARNING) << "Unknown message received!"; |
[email protected] | a95986a8 | 2010-12-24 06:19:28 | [diff] [blame] | 201 | return false; |
[email protected] | 5a8db80 | 2010-10-06 17:34:43 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | void CFProxy::OnChannelConnected(int32 peer_pid) { |
| 205 | is_connected_ = true; |
| 206 | // TODO(stoyan): May be we should wait for Hello message. |
| 207 | for (DelegateList::iterator it = delegate_list_.begin(); |
| 208 | it != delegate_list_.end(); ++it) { |
| 209 | (*it)->Connected(this); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | void CFProxy::OnChannelError() { |
| 214 | is_connected_ = false; |
| 215 | |
| 216 | // Inform the sync message callbacks that there are not going to see |
| 217 | // any reply. |
| 218 | sync_dispatcher_.OnChannelClosed(); |
| 219 | OnPeerLost(ChromeProxyDelegate::CHANNEL_ERROR); |
| 220 | |
| 221 | // TODO(stoyan): Relaunch? |
| 222 | } |