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 |