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/bind_helpers.h"
9 #include "base/tuple.h"
10 #include "ipc/ipc_sync_message.h"
11 #include "chrome/common/automation_messages.h"
13 CFProxy::CFProxy(CFProxyTraits
* api
) : ipc_thread_("ipc"),
14 sync_dispatcher_(&tab2delegate_
),
18 is_connected_(false) {
22 ipc_thread_
.message_loop()->PostTask(
24 base::Bind(&CFProxy::CleanupOnIoThread
, base::Unretained(this)));
25 // ipc_thread destructor will do the Stop anyway. this is for debug :)
29 void CFProxy::Init(const ProxyParams
& params
) {
30 ipc_thread_
.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO
, 0));
31 ipc_thread_
.message_loop()->PostTask(
33 base::Bind(&CFProxy::InitInIoThread
, base::Unretained(this), params
));
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_
;
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_
;
50 void CFProxy::AddDelegateOnIoThread(ChromeProxyDelegate
* delegate
) {
51 DCHECK(CalledOnIpcThread());
52 DelegateHolder::AddDelegate(delegate
);
54 delegate
->Connected(this);
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();
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
,
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());
77 OnPeerLost(ChromeProxyDelegate::CHROME_EXE_LAUNCH_FAILED
);
81 void CFProxy::CleanupOnIoThread() {
82 DCHECK(CalledOnIpcThread());
84 api_
->CloseChannel(ipc_sender_
);
87 // TODO(stoyan): shall we notify delegates?
88 // The object is dying, so under normal circumstances there should be
90 DCHECK_EQ(0, delegate_count_
);
91 DCHECK_EQ(0u, delegate_list_
.size());
92 DCHECK_EQ(0u, tab2delegate_
.size());
95 void CFProxy::LaunchTimeOut() {
96 DCHECK(CalledOnIpcThread());
98 OnPeerLost(ChromeProxyDelegate::CHROME_EXE_LAUNCH_TIMEOUT
);
102 void CFProxy::OnPeerLost(ChromeProxyDelegate::DisconnectReason reason
) {
103 // Kill the channel. Inform delegates
104 DCHECK(CalledOnIpcThread());
106 api_
->CloseChannel(ipc_sender_
);
110 for (DelegateList::iterator it
= delegate_list_
.begin();
111 it
!= delegate_list_
.end(); ++it
) {
112 (*it
)->PeerLost(this, reason
);
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
));
122 void CFProxy::SendIpcMessageOnIoThread(IPC::Message
* m
) {
123 DCHECK(CalledOnIpcThread());
125 ipc_sender_
->Send(m
);
131 //////////////////////////////////////////////////////////////////////////
133 void CFProxy::Tab_Find(int tab
, const string16
& search_string
,
134 FindInPageDirection forward
, FindInPageCase match_case
,
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
);
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
);
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
);
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
);
170 void CFProxy::ConnectTab(ChromeProxyDelegate
* delegate
, HWND hwnd
,
172 IPC::SyncMessage
* m
= new AutomationMsg_ConnectExternalTab(cookie
, true,
173 hwnd
, NULL
, NULL
, NULL
, 0);
174 sync_dispatcher_
.QueueSyncMessage(m
, delegate
, NULL
);
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
);
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
);
192 // IPC::Channel::Listener
193 bool CFProxy::OnMessageReceived(const IPC::Message
& message
) {
194 // Handle sync message reply.
195 bool done
= sync_dispatcher_
.OnReplyReceived(&message
);
199 // Handle tab related message.
200 ChromeProxyDelegate
* d
= Tab2Delegate(message
.routing_id());
202 return d
->OnMessageReceived(message
);
204 DLOG(WARNING
) << "Unknown message received!";
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);
217 void CFProxy::OnChannelError() {
218 is_connected_
= false;
220 // Inform the sync message callbacks that there are not going to see
222 sync_dispatcher_
.OnChannelClosed();
223 OnPeerLost(ChromeProxyDelegate::CHANNEL_ERROR
);
225 // TODO(stoyan): Relaunch?