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