OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/client/jni/chromoting_jni_instance.h" | 5 #include "remoting/client/jni/chromoting_jni_instance.h" |
6 | 6 |
7 #include "base/android/base_jni_registrar.h" | |
8 #include "base/android/jni_android.h" | |
9 #include "base/bind.h" | 7 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | |
11 #include "base/logging.h" | 8 #include "base/logging.h" |
12 #include "base/memory/singleton.h" | |
13 #include "net/android/net_jni_registrar.h" | |
14 #include "remoting/base/url_request_context.h" | |
15 #include "remoting/client/audio_player.h" | 9 #include "remoting/client/audio_player.h" |
| 10 #include "remoting/client/jni/chromoting_jni.h" |
16 #include "remoting/protocol/libjingle_transport_factory.h" | 11 #include "remoting/protocol/libjingle_transport_factory.h" |
17 | 12 |
| 13 namespace { |
| 14 // TODO(solb) Move into location shared with client plugin. |
| 15 const char* const CHAT_SERVER = "talk.google.com"; |
| 16 const int CHAT_PORT = 5222; |
| 17 const bool CHAT_USE_TLS = true; |
| 18 const char* const CHAT_AUTH_METHOD = "oauth2"; |
| 19 } // namespace |
| 20 |
18 namespace remoting { | 21 namespace remoting { |
19 | 22 |
20 // static | 23 ChromotingJniInstance::ChromotingJniInstance(const char* username, |
21 ChromotingJNIInstance* ChromotingJNIInstance::GetInstance() { | 24 const char* auth_token, |
22 return Singleton<ChromotingJNIInstance>::get(); | 25 const char* host_jid, |
23 } | 26 const char* host_id, |
24 | 27 const char* host_pubkey) { |
25 ChromotingJNIInstance::ChromotingJNIInstance() | 28 DCHECK(ChromotingJni::GetInstance()-> |
26 : connected_(false) { | 29 ui_task_runner()->BelongsToCurrentThread()); |
27 JNIEnv* env = base::android::AttachCurrentThread(); | |
28 | |
29 // The base and networks stacks must be registered with JNI in order to work | |
30 // on Android. An AtExitManager cleans this up at world's end. | |
31 collector_.reset(new base::AtExitManager()); | |
32 base::android::RegisterJni(env); | |
33 net::android::RegisterJni(env); | |
34 | |
35 // On Android, the UI thread is managed by Java, so we need to attach and | |
36 // start a special type of message loop to allow Chromium code to run tasks. | |
37 LOG(INFO) << "Starting main message loop"; | |
38 ui_loop_.reset(new base::MessageLoopForUI()); | |
39 ui_loop_->Start(); | |
40 | |
41 LOG(INFO) << "Spawning additional threads"; | |
42 // TODO(solb) Stop pretending to control the managed UI thread's lifetime. | |
43 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(), | |
44 base::MessageLoop::QuitClosure()); | |
45 network_task_runner_ = AutoThread::CreateWithType("native_net", | |
46 ui_task_runner_, | |
47 base::MessageLoop::TYPE_IO); | |
48 display_task_runner_ = AutoThread::Create("native_disp", | |
49 ui_task_runner_); | |
50 | |
51 url_requester_ = new URLRequestContextGetter(ui_task_runner_, | |
52 network_task_runner_); | |
53 | |
54 class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(JAVA_CLASS))); | |
55 } | |
56 | |
57 ChromotingJNIInstance::~ChromotingJNIInstance() { | |
58 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
59 DCHECK(!connected_); | |
60 | |
61 JNIEnv* env = base::android::AttachCurrentThread(); | |
62 env->DeleteGlobalRef(class_); | |
63 // TODO(solb): crbug.com/259594 Detach all threads from JVM here. | |
64 } | |
65 | |
66 void ChromotingJNIInstance::ConnectToHost(const char* username, | |
67 const char* auth_token, | |
68 const char* host_jid, | |
69 const char* host_id, | |
70 const char* host_pubkey) { | |
71 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
72 DCHECK(!connected_); | |
73 connected_ = true; | |
74 | 30 |
75 username_ = username; | 31 username_ = username; |
76 auth_token_ = auth_token; | 32 auth_token_ = auth_token; |
77 host_jid_ = host_jid; | 33 host_jid_ = host_jid; |
78 host_id_ = host_id; | 34 host_id_ = host_id; |
79 host_pubkey_ = host_pubkey; | 35 host_pubkey_ = host_pubkey; |
80 | 36 |
81 display_task_runner_->PostTask(FROM_HERE, base::Bind( | 37 ChromotingJni::GetInstance()->display_task_runner()->PostTask( |
82 &ChromotingJNIInstance::ConnectToHostOnDisplayThread, | 38 FROM_HERE, |
83 base::Unretained(this))); | 39 base::Bind(&ChromotingJniInstance::ConnectToHostOnDisplayThread, |
| 40 this)); |
84 } | 41 } |
85 | 42 |
86 void ChromotingJNIInstance::DisconnectFromHost() { | 43 ChromotingJniInstance::~ChromotingJniInstance() {} |
87 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
88 DCHECK(connected_); | |
89 connected_ = false; | |
90 | 44 |
91 network_task_runner_->PostTask(FROM_HERE, base::Bind( | 45 void ChromotingJniInstance::Cleanup() { |
92 &ChromotingJNIInstance::DisconnectFromHostOnNetworkThread, | 46 if (!ChromotingJni::GetInstance()-> |
93 base::Unretained(this))); | 47 network_task_runner()->BelongsToCurrentThread()) { |
| 48 ChromotingJni::GetInstance()->network_task_runner()->PostTask( |
| 49 FROM_HERE, |
| 50 base::Bind(&ChromotingJniInstance::Cleanup, this)); |
| 51 return; |
| 52 } |
| 53 |
| 54 username_ = ""; |
| 55 auth_token_ = ""; |
| 56 host_jid_ = ""; |
| 57 host_id_ = ""; |
| 58 host_pubkey_ = ""; |
| 59 |
| 60 // |client_| must be torn down before |signaling_|. |
| 61 pin_callback_.Reset(); |
| 62 client_.reset(); |
| 63 connection_.reset(); |
| 64 client_context_.reset(); |
| 65 client_config_.reset(); |
| 66 signaling_.reset(); |
| 67 signaling_config_.reset(); |
| 68 network_settings_.reset(); |
94 } | 69 } |
95 | 70 |
96 void ChromotingJNIInstance::ProvideSecret(const char* pin) { | 71 void ChromotingJniInstance::ProvideSecret(const char* pin) { |
97 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 72 DCHECK(ChromotingJni::GetInstance()-> |
| 73 ui_task_runner()->BelongsToCurrentThread()); |
98 DCHECK(!pin_callback_.is_null()); | 74 DCHECK(!pin_callback_.is_null()); |
99 | 75 |
100 // We invoke the string constructor to ensure |pin| gets copied *before* the | 76 // We invoke the string constructor to ensure |pin| gets copied *before* the |
101 // asynchronous run, since Java might want it back as soon as we return. | 77 // asynchronous run, since Java might want it back as soon as we return. |
102 network_task_runner_->PostTask(FROM_HERE, | 78 ChromotingJni::GetInstance()->network_task_runner()->PostTask(FROM_HERE, |
103 base::Bind(pin_callback_, std::string(pin))); | 79 base::Bind(pin_callback_, pin)); |
104 } | 80 } |
105 | 81 |
106 void ChromotingJNIInstance::OnConnectionState( | 82 void ChromotingJniInstance::OnConnectionState( |
107 protocol::ConnectionToHost::State state, | 83 protocol::ConnectionToHost::State state, |
108 protocol::ErrorCode error) { | 84 protocol::ErrorCode error) { |
109 if (!ui_task_runner_->BelongsToCurrentThread()) { | 85 if (!ChromotingJni::GetInstance()-> |
110 ui_task_runner_->PostTask(FROM_HERE, base::Bind( | 86 ui_task_runner()->BelongsToCurrentThread()) { |
111 &ChromotingJNIInstance::OnConnectionState, | 87 ChromotingJni::GetInstance()-> |
112 base::Unretained(this), | 88 ui_task_runner()->PostTask( |
113 state, | 89 FROM_HERE, |
114 error)); | 90 base::Bind(&ChromotingJniInstance::OnConnectionState, |
| 91 this, |
| 92 state, |
| 93 error)); |
115 return; | 94 return; |
116 } | 95 } |
117 | 96 |
118 JNIEnv* env = base::android::AttachCurrentThread(); | 97 ChromotingJni::GetInstance()->ReportConnectionStatus(state, error); |
119 env->CallStaticVoidMethod( | |
120 class_, | |
121 env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"), | |
122 state, | |
123 error); | |
124 } | 98 } |
125 | 99 |
126 void ChromotingJNIInstance::OnConnectionReady(bool ready) { | 100 void ChromotingJniInstance::OnConnectionReady(bool ready) { |
127 // We ignore this message, since OnConnectionState() tells us the same thing. | 101 // We ignore this message, since OnConnectionState() tells us the same thing. |
128 } | 102 } |
129 | 103 |
130 void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {} | 104 void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {} |
131 | 105 |
132 void ChromotingJNIInstance::SetPairingResponse( | 106 void ChromotingJniInstance::SetPairingResponse( |
133 const protocol::PairingResponse& response) { | 107 const protocol::PairingResponse& response) { |
134 NOTIMPLEMENTED(); | 108 NOTIMPLEMENTED(); |
135 } | 109 } |
136 | 110 |
137 protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() { | 111 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() { |
138 NOTIMPLEMENTED(); | 112 NOTIMPLEMENTED(); |
139 return NULL; | 113 return NULL; |
140 } | 114 } |
141 | 115 |
142 protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() { | 116 protocol::CursorShapeStub* ChromotingJniInstance::GetCursorShapeStub() { |
143 NOTIMPLEMENTED(); | 117 NOTIMPLEMENTED(); |
144 return NULL; | 118 return NULL; |
145 } | 119 } |
146 | 120 |
147 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> | 121 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> |
148 ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) { | 122 ChromotingJniInstance::GetTokenFetcher(const std::string& host_public_key) { |
149 // Return null to indicate that third-party authentication is unsupported. | 123 // Return null to indicate that third-party authentication is unsupported. |
150 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); | 124 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); |
151 } | 125 } |
152 | 126 |
153 void ChromotingJNIInstance::ConnectToHostOnDisplayThread() { | 127 void ChromotingJniInstance::ConnectToHostOnDisplayThread() { |
154 DCHECK(display_task_runner_->BelongsToCurrentThread()); | 128 DCHECK(ChromotingJni::GetInstance()-> |
| 129 display_task_runner()->BelongsToCurrentThread()); |
155 | 130 |
156 if (!frame_consumer_.get()) { | 131 if (!frame_consumer_.get()) { |
157 frame_consumer_ = new FrameConsumerProxy(display_task_runner_); | 132 frame_consumer_ = new FrameConsumerProxy( |
| 133 ChromotingJni::GetInstance()->display_task_runner()); |
158 // TODO(solb) Instantiate some FrameConsumer implementation and attach it. | 134 // TODO(solb) Instantiate some FrameConsumer implementation and attach it. |
159 } | 135 } |
160 | 136 |
161 network_task_runner_->PostTask(FROM_HERE, base::Bind( | 137 ChromotingJni::GetInstance()->network_task_runner()->PostTask( |
162 &ChromotingJNIInstance::ConnectToHostOnNetworkThread, | 138 FROM_HERE, |
163 base::Unretained(this))); | 139 base::Bind(&ChromotingJniInstance::ConnectToHostOnNetworkThread, |
| 140 this)); |
164 } | 141 } |
165 | 142 |
166 void ChromotingJNIInstance::ConnectToHostOnNetworkThread() { | 143 void ChromotingJniInstance::ConnectToHostOnNetworkThread() { |
167 DCHECK(network_task_runner_->BelongsToCurrentThread()); | 144 DCHECK(ChromotingJni::GetInstance()-> |
| 145 network_task_runner()->BelongsToCurrentThread()); |
168 | 146 |
169 client_config_.reset(new ClientConfig()); | 147 client_config_.reset(new ClientConfig()); |
170 client_config_->host_jid = host_jid_; | 148 client_config_->host_jid = host_jid_; |
171 client_config_->host_public_key = host_pubkey_; | 149 client_config_->host_public_key = host_pubkey_; |
172 | 150 |
173 client_config_->fetch_secret_callback = base::Bind( | 151 client_config_->fetch_secret_callback = base::Bind( |
174 &ChromotingJNIInstance::FetchSecret, | 152 &ChromotingJniInstance::FetchSecret, |
175 base::Unretained(this)); | 153 this); |
176 client_config_->authentication_tag = host_id_; | 154 client_config_->authentication_tag = host_id_; |
177 | 155 |
178 // TODO(solb) Move these hardcoded values elsewhere: | 156 // TODO(solb) Move these hardcoded values elsewhere: |
179 client_config_->authentication_methods.push_back( | 157 client_config_->authentication_methods.push_back( |
180 protocol::AuthenticationMethod::FromString("spake2_hmac")); | 158 protocol::AuthenticationMethod::FromString("spake2_hmac")); |
181 client_config_->authentication_methods.push_back( | 159 client_config_->authentication_methods.push_back( |
182 protocol::AuthenticationMethod::FromString("spake2_plain")); | 160 protocol::AuthenticationMethod::FromString("spake2_plain")); |
183 | 161 |
184 client_context_.reset(new ClientContext(network_task_runner_.get())); | 162 client_context_.reset(new ClientContext( |
| 163 ChromotingJni::GetInstance()->network_task_runner().get())); |
185 client_context_->Start(); | 164 client_context_->Start(); |
186 | 165 |
187 connection_.reset(new protocol::ConnectionToHost(true)); | 166 connection_.reset(new protocol::ConnectionToHost(true)); |
188 | 167 |
189 client_.reset(new ChromotingClient(*client_config_, | 168 client_.reset(new ChromotingClient(*client_config_, |
190 client_context_.get(), | 169 client_context_.get(), |
191 connection_.get(), | 170 connection_.get(), |
192 this, | 171 this, |
193 frame_consumer_, | 172 frame_consumer_, |
194 scoped_ptr<AudioPlayer>())); | 173 scoped_ptr<AudioPlayer>())); |
195 | 174 |
196 signaling_config_.reset(new XmppSignalStrategy::XmppServerConfig()); | 175 signaling_config_.reset(new XmppSignalStrategy::XmppServerConfig()); |
197 signaling_config_->host = CHAT_SERVER; | 176 signaling_config_->host = CHAT_SERVER; |
198 signaling_config_->port = CHAT_PORT; | 177 signaling_config_->port = CHAT_PORT; |
199 signaling_config_->use_tls = CHAT_USE_TLS; | 178 signaling_config_->use_tls = CHAT_USE_TLS; |
200 | 179 |
201 signaling_.reset(new XmppSignalStrategy(url_requester_, | 180 signaling_.reset(new XmppSignalStrategy( |
202 username_, | 181 ChromotingJni::GetInstance()->url_requester(), |
203 auth_token_, | 182 username_, |
204 CHAT_AUTH_METHOD, | 183 auth_token_, |
205 *signaling_config_)); | 184 CHAT_AUTH_METHOD, |
| 185 *signaling_config_)); |
206 | 186 |
207 network_settings_.reset(new NetworkSettings( | 187 network_settings_.reset(new NetworkSettings( |
208 NetworkSettings::NAT_TRAVERSAL_OUTGOING)); | 188 NetworkSettings::NAT_TRAVERSAL_OUTGOING)); |
209 scoped_ptr<protocol::TransportFactory> fact( | 189 scoped_ptr<protocol::TransportFactory> fact( |
210 protocol::LibjingleTransportFactory::Create(*network_settings_, | 190 protocol::LibjingleTransportFactory::Create( |
211 url_requester_)); | 191 *network_settings_, |
| 192 ChromotingJni::GetInstance()->url_requester())); |
212 | 193 |
213 client_->Start(signaling_.get(), fact.Pass()); | 194 client_->Start(signaling_.get(), fact.Pass()); |
214 } | 195 } |
215 | 196 |
216 void ChromotingJNIInstance::DisconnectFromHostOnNetworkThread() { | 197 void ChromotingJniInstance::FetchSecret( |
217 DCHECK(network_task_runner_->BelongsToCurrentThread()); | |
218 | |
219 username_ = ""; | |
220 auth_token_ = ""; | |
221 host_jid_ = ""; | |
222 host_id_ = ""; | |
223 host_pubkey_ = ""; | |
224 | |
225 // |client_| must be torn down before |signaling_|. | |
226 pin_callback_.Reset(); | |
227 client_.reset(); | |
228 connection_.reset(); | |
229 client_context_.reset(); | |
230 client_config_.reset(); | |
231 signaling_.reset(); | |
232 signaling_config_.reset(); | |
233 network_settings_.reset(); | |
234 } | |
235 | |
236 void ChromotingJNIInstance::FetchSecret( | |
237 bool pairable, | 198 bool pairable, |
238 const protocol::SecretFetchedCallback& callback) { | 199 const protocol::SecretFetchedCallback& callback) { |
239 if (!ui_task_runner_->BelongsToCurrentThread()) { | 200 if (!ChromotingJni::GetInstance()-> |
240 ui_task_runner_->PostTask(FROM_HERE, base::Bind( | 201 ui_task_runner()->BelongsToCurrentThread()) { |
241 &ChromotingJNIInstance::FetchSecret, | 202 ChromotingJni::GetInstance()->ui_task_runner()->PostTask( |
242 base::Unretained(this), | 203 FROM_HERE, |
243 pairable, | 204 base::Bind(&ChromotingJniInstance::FetchSecret, |
244 callback)); | 205 this, |
| 206 pairable, |
| 207 callback)); |
245 return; | 208 return; |
246 } | 209 } |
247 | 210 |
248 pin_callback_ = callback; | 211 pin_callback_ = callback; |
249 JNIEnv* env = base::android::AttachCurrentThread(); | 212 ChromotingJni::GetInstance()->DisplayAuthenticationPrompt(); |
250 env->CallStaticVoidMethod( | |
251 class_, | |
252 env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V")); | |
253 } | 213 } |
254 | 214 |
255 } // namespace remoting | 215 } // namespace remoting |
OLD | NEW |