Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: remoting/client/jni/chromoting_jni_instance.cc

Issue 18612018: Restructure chromoting_jni_instance handling of Java strings (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase on top of issue 18477010 Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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" 7 #include "base/android/base_jni_registrar.h"
8 #include "base/android/jni_android.h" 8 #include "base/android/jni_android.h"
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/singleton.h" 12 #include "base/memory/singleton.h"
13 #include "net/android/net_jni_registrar.h" 13 #include "net/android/net_jni_registrar.h"
14 #include "remoting/base/url_request_context.h" 14 #include "remoting/base/url_request_context.h"
15 #include "remoting/client/audio_player.h" 15 #include "remoting/client/audio_player.h"
16 #include "remoting/protocol/libjingle_transport_factory.h" 16 #include "remoting/protocol/libjingle_transport_factory.h"
17 17
18 namespace remoting { 18 namespace remoting {
19 19
20 // static 20 // static
21 ChromotingJNIInstance* ChromotingJNIInstance::GetInstance() { 21 ChromotingJNIInstance* ChromotingJNIInstance::GetInstance() {
22 return Singleton<ChromotingJNIInstance>::get(); 22 return Singleton<ChromotingJNIInstance>::get();
23 } 23 }
24 24
25 ChromotingJNIInstance::ChromotingJNIInstance() 25 ChromotingJNIInstance::ChromotingJNIInstance() {
26 : username_cstr_(NULL),
27 auth_token_cstr_(NULL),
28 host_jid_cstr_(NULL),
29 host_id_cstr_(NULL),
30 host_pubkey_cstr_(NULL),
31 pin_cstr_(NULL) {
32 JNIEnv* env = base::android::AttachCurrentThread(); 26 JNIEnv* env = base::android::AttachCurrentThread();
33 27
28 // The base and networks stacks must be registered with the JNI in order to
Wez 2013/07/11 22:32:08 nit: the JNI -> JNI
solb 2013/07/11 23:59:09 Done.
29 // work on Android. A (required) AtExitManager cleans this up at world's end.
Wez 2013/07/11 22:32:08 nit: why is (required) needed here?
solb 2013/07/11 23:59:09 Done.
34 collector_.reset(new base::AtExitManager()); 30 collector_.reset(new base::AtExitManager());
35 base::android::RegisterJni(env); 31 base::android::RegisterJni(env);
36 net::android::RegisterJni(env); 32 net::android::RegisterJni(env);
37 33
38 LOG(INFO) << "starting main message loop"; 34 // On Android, the UI thread is managed by the Java side of things, so we
Wez 2013/07/11 22:32:08 nit: by the Java side of things -> by Java
solb 2013/07/11 23:59:09 Done.
35 // need to attach and start a special type of message loop in order to allow
36 // Chromium code to queue tasks there.
37 LOG(INFO) << "Starting main message loop";
39 ui_loop_.reset(new base::MessageLoopForUI()); 38 ui_loop_.reset(new base::MessageLoopForUI());
40 ui_loop_->Start(); 39 ui_loop_->Start();
41 40
42 LOG(INFO) << "spawning additional threads"; 41 LOG(INFO) << "Spawning additional threads";
43 ui_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(), 42 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
44 base::MessageLoop::QuitClosure()); 43 base::MessageLoop::QuitClosure());
45 net_runner_ = AutoThread::CreateWithType("native_net", 44 network_task_runner_ = AutoThread::CreateWithType("native_net",
46 ui_runner_, 45 ui_task_runner_,
47 base::MessageLoop::TYPE_IO); 46 base::MessageLoop::TYPE_IO);
48 disp_runner_ = AutoThread::CreateWithType("native_disp", 47 display_task_runner_ = AutoThread::CreateWithType("native_disp",
49 ui_runner_, 48 ui_task_runner_,
50 base::MessageLoop::TYPE_DEFAULT); 49 base::MessageLoop::TYPE_DEFAULT);
51 50
52 url_requester_ = new URLRequestContextGetter(ui_runner_, net_runner_); 51 url_requester_ = new URLRequestContextGetter(ui_task_runner_,
52 network_task_runner_);
53 53
54 class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(JAVA_CLASS))); 54 class_ = static_cast<jclass>(env->NewGlobalRef(env->FindClass(JAVA_CLASS)));
55 } 55 }
56 56
57 ChromotingJNIInstance::~ChromotingJNIInstance() { 57 ChromotingJNIInstance::~ChromotingJNIInstance() {
58 JNIEnv* env = base::android::AttachCurrentThread(); 58 JNIEnv* env = base::android::AttachCurrentThread();
59 env->DeleteGlobalRef(class_); 59 env->DeleteGlobalRef(class_);
60 // TODO(solb) detach all threads from JVM 60 // TODO(solb) detach all threads from JVM
Wez 2013/07/11 22:32:08 Why the TODO?
solb 2013/07/11 23:59:09 As I mentioned in a prior CL, it's something I pla
Wez 2013/07/12 00:24:48 OK, please file a bug for that work and refer to i
Wez 2013/07/12 01:25:44 Ping.
61 } 61 }
62 62
63 void ChromotingJNIInstance::ConnectToHost(jstring username, 63 void ChromotingJNIInstance::ConnectToHost(const char* username,
64 jstring auth_token, 64 const char* auth_token,
65 jstring host_jid, 65 const char* host_jid,
66 jstring host_id, 66 const char* host_id,
67 jstring host_pubkey) { 67 const char* host_pubkey) {
Wez 2013/07/11 22:32:08 nit: DCHECK() that you're called on the expected t
solb 2013/07/11 23:59:09 The threading of this method has become less impor
Wez 2013/07/12 00:24:48 Don't other threads read these values, though? Are
68 JNIEnv* env = base::android::AttachCurrentThread(); 68 username_ = username;
69 69 auth_token_ = auth_token;
70 username_jstr_ = static_cast<jstring>(env->NewGlobalRef(username)); 70 host_jid_ = host_jid;
71 auth_token_jstr_ = static_cast<jstring>(env->NewGlobalRef(auth_token)); 71 host_id_ = host_id;
72 host_jid_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_jid)); 72 host_pubkey_ = host_pubkey;
73 host_id_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_id));
74 host_pubkey_jstr_ = static_cast<jstring>(env->NewGlobalRef(host_pubkey));
75
76 username_cstr_ = env->GetStringUTFChars(username_jstr_, NULL);
77 auth_token_cstr_ = env->GetStringUTFChars(auth_token_jstr_, NULL);
78 host_jid_cstr_ = env->GetStringUTFChars(host_jid_jstr_, NULL);
79 host_id_cstr_ = env->GetStringUTFChars(host_id_jstr_, NULL);
80 host_pubkey_cstr_ = env->GetStringUTFChars(host_pubkey_jstr_, NULL);
81 73
82 // We're a singleton, so Unretained is safe here. 74 // We're a singleton, so Unretained is safe here.
83 disp_runner_->PostTask(FROM_HERE, base::Bind( 75 display_task_runner_->PostTask(FROM_HERE, base::Bind(
84 &ChromotingJNIInstance::ConnectToHostOnDisplayThread, 76 &ChromotingJNIInstance::ConnectToHostOnDisplayThread,
85 base::Unretained(this))); 77 base::Unretained(this)));
86 } 78 }
87 79
88 void ChromotingJNIInstance::DisconnectFromHost() { 80 void ChromotingJNIInstance::DisconnectFromHost() {
89 JNIEnv* env = base::android::AttachCurrentThread(); 81 // All our work must be done on the network thread.
Wez 2013/07/11 22:32:08 ConnectToHost seems to store the strings while on
solb 2013/07/11 23:59:09 Done.
90 82 if (!network_task_runner_->BelongsToCurrentThread()) {
91 env->ReleaseStringUTFChars(username_jstr_, username_cstr_); 83 // We're a singleton, so Unretained is safe here.
Wez 2013/07/11 22:32:08 Why does being a singleton make it safe? Who delet
solb 2013/07/11 23:59:09 The singleton is deleted automatically at exit, wh
Wez 2013/07/12 00:24:48 Ah, OK, so the guarantee is that the object will o
Wez 2013/07/12 01:25:44 Blah... by which time there can be no further pend
92 env->ReleaseStringUTFChars(auth_token_jstr_, auth_token_cstr_); 84 network_task_runner_->PostTask(FROM_HERE, base::Bind(
93 env->ReleaseStringUTFChars(host_jid_jstr_, host_jid_cstr_); 85 &ChromotingJNIInstance::DisconnectFromHost,
94 env->ReleaseStringUTFChars(host_id_jstr_, host_id_cstr_); 86 base::Unretained(this)));
95 env->ReleaseStringUTFChars(host_pubkey_jstr_, host_pubkey_cstr_); 87 return;
96
97 username_cstr_ = NULL;
98 auth_token_cstr_ = NULL;
99 host_jid_cstr_ = NULL;
100 host_id_cstr_ = NULL;
101 host_pubkey_cstr_ = NULL;
102
103 env->DeleteGlobalRef(username_jstr_);
104 env->DeleteGlobalRef(auth_token_jstr_);
105 env->DeleteGlobalRef(host_jid_jstr_);
106 env->DeleteGlobalRef(host_id_jstr_);
107 env->DeleteGlobalRef(host_pubkey_jstr_);
108
109 if (pin_cstr_) {
110 // AuthenticatedWithPin() has been called.
111 env->ReleaseStringUTFChars(pin_jstr_, pin_cstr_);
112 pin_cstr_ = NULL;
113 env->DeleteGlobalRef(pin_jstr_);
114 } 88 }
115 89
116 // We're a singleton, so Unretained is safe here. 90 client_.reset();
117 net_runner_->PostTask(FROM_HERE, base::Bind( 91 connection_.reset();
118 &ChromotingJNIInstance::DisconnectFromHostOnNetworkThread, 92 client_context_.reset();
119 base::Unretained(this))); 93 client_config_.reset();
94 chat_.reset(); // This object must outlive client_.
Wez 2013/07/11 22:32:08 nit: Suggest putting a comment before |client_| "|
solb 2013/07/11 23:59:09 Done.
95 chat_config_.reset(); // TODO(solb) Restructure to reuse between sessions.
Wez 2013/07/11 22:32:08 Either remove this TODO or elaborate on what you i
solb 2013/07/11 23:59:09 Done.
96 netset_.reset();
120 } 97 }
121 98
122 void ChromotingJNIInstance::AuthenticateWithPin(jstring pin) { 99 void ChromotingJNIInstance::AuthenticateWithPin(const char* pin) {
123 JNIEnv* env = base::android::AttachCurrentThread(); 100 pin_ = pin;
124 101 network_task_runner_->PostTask(FROM_HERE, base::Bind(announce_secret_, pin_));
125 pin_jstr_ = static_cast<jstring>(env->NewGlobalRef(pin));
126 pin_cstr_ = env->GetStringUTFChars(pin_jstr_, NULL);
127
128 net_runner_->PostTask(FROM_HERE, base::Bind(announce_secret_, pin_cstr_));
129 } 102 }
130 103
131 void ChromotingJNIInstance::FetchSecret( 104 void ChromotingJNIInstance::FetchSecret(
132 bool pairable, 105 bool pairable,
133 const protocol::SecretFetchedCallback& callback_encore) { 106 const protocol::SecretFetchedCallback& callback) {
134 // All our work must be done on the UI thread. 107 // All our work must be done on the UI thread.
Wez 2013/07/11 22:32:08 Previous method says network thread, not UI thread
solb 2013/07/11 23:59:09 I believe it's correct as written. This method is
135 if (!ui_runner_->BelongsToCurrentThread()) { 108 if (!ui_task_runner_->BelongsToCurrentThread()) {
136 // We're a singleton, so Unretained is safe here. 109 // We're a singleton, so Unretained is safe here.
137 ui_runner_->PostTask(FROM_HERE, base::Bind( 110 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
138 &ChromotingJNIInstance::FetchSecret, 111 &ChromotingJNIInstance::FetchSecret,
139 base::Unretained(this), 112 base::Unretained(this),
140 pairable, 113 pairable,
141 callback_encore)); 114 callback));
142 return; 115 return;
143 } 116 }
144 117
145 announce_secret_ = callback_encore; 118 announce_secret_ = callback;
146 JNIEnv* env = base::android::AttachCurrentThread(); 119 JNIEnv* env = base::android::AttachCurrentThread();
147 env->CallStaticVoidMethod( 120 env->CallStaticVoidMethod(
148 class_, 121 class_,
149 env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V")); 122 env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V"));
150 } 123 }
151 124
152 void ChromotingJNIInstance::OnConnectionState( 125 void ChromotingJNIInstance::OnConnectionState(
153 protocol::ConnectionToHost::State state, 126 protocol::ConnectionToHost::State state,
154 protocol::ErrorCode error) { 127 protocol::ErrorCode error) {
155 // All our work must be done on the UI thread. 128 // All our work must be done on the UI thread.
Wez 2013/07/11 22:32:08 Here too
solb 2013/07/11 23:59:09 Once again, we're invoked on the network thread bu
Wez 2013/07/12 00:24:48 See comment above; no need for this comment at all
156 if (!ui_runner_->BelongsToCurrentThread()) { 129 if (!ui_task_runner_->BelongsToCurrentThread()) {
157 // We're a singleton, so Unretained is safe here. 130 // We're a singleton, so Unretained is safe here.
158 ui_runner_->PostTask(FROM_HERE, base::Bind( 131 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
159 &ChromotingJNIInstance::OnConnectionState, 132 &ChromotingJNIInstance::OnConnectionState,
160 base::Unretained(this), 133 base::Unretained(this),
161 state, 134 state,
162 error)); 135 error));
163 return; 136 return;
164 } 137 }
165 138
166 JNIEnv* env = base::android::AttachCurrentThread(); 139 JNIEnv* env = base::android::AttachCurrentThread();
167 env->CallStaticVoidMethod( 140 env->CallStaticVoidMethod(
168 class_, 141 class_,
169 env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"), 142 env->GetStaticMethodID(class_, "reportConnectionStatus", "(II)V"),
170 state, 143 state,
171 error); 144 error);
172 } 145 }
173 146
174 void ChromotingJNIInstance::OnConnectionReady(bool ready) { 147 // We ignore this message, since OnConnectionState() tells us the same thing.
Wez 2013/07/11 22:32:08 nit: Move this into the body of the method
solb 2013/07/11 23:59:09 Done.
175 } 148 void ChromotingJNIInstance::OnConnectionReady(bool ready) {}
Wez 2013/07/11 22:32:08 Why do both exist, then?
solb 2013/07/11 23:59:09 Done.
176 149
150 // We ignore this message because we don't deal with capabilities.
Wez 2013/07/11 22:32:08 You don't really need this comment; it's clear fro
solb 2013/07/11 23:59:09 Done.
177 void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {} 151 void ChromotingJNIInstance::SetCapabilities(const std::string& capabilities) {}
178 152
153 // We ignore this message because OnConnectionState() reveals the same info.
Wez 2013/07/11 22:32:08 nit: Move this comment into the body of the method
solb 2013/07/11 23:59:09 Done.
179 void ChromotingJNIInstance::SetPairingResponse( 154 void ChromotingJNIInstance::SetPairingResponse(
180 const protocol::PairingResponse& response) {} 155 const protocol::PairingResponse& response) {
156 }
181 157
182 protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() { 158 protocol::ClipboardStub* ChromotingJNIInstance::GetClipboardStub() {
183 NOTIMPLEMENTED(); 159 NOTIMPLEMENTED();
184 return NULL; 160 return NULL;
185 } 161 }
186 162
187 protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() { 163 protocol::CursorShapeStub* ChromotingJNIInstance::GetCursorShapeStub() {
188 NOTIMPLEMENTED(); 164 NOTIMPLEMENTED();
189 return NULL; 165 return NULL;
190 } 166 }
191 167
192 // We don't use NOTIMPLEMENTED() here because NegotiatingClientAuthenticator 168 // We don't support third party authentication, so we return a null pointer.
Wez 2013/07/11 22:32:08 nit: Move this inside the method, and reword e.g.
solb 2013/07/11 23:59:09 Done.
193 // calls this even if it doesn't use the configuration method, and we don't
194 // want to print an error on every run.
195 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> 169 scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
196 ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) { 170 ChromotingJNIInstance::GetTokenFetcher(const std::string& host_public_key) {
197 LOG(INFO) << "ChromotingJNIInstance::GetTokenFetcher(...) [unimplemented]";
198 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>(); 171 return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
199 } 172 }
200 173
201 void ChromotingJNIInstance::ConnectToHostOnDisplayThread() { 174 void ChromotingJNIInstance::ConnectToHostOnDisplayThread() {
202 DCHECK(disp_runner_->BelongsToCurrentThread()); 175 DCHECK(display_task_runner_->BelongsToCurrentThread());
203 176
204 if (!frames_.get()) { 177 if (!frames_.get()) {
205 frames_ = new FrameConsumerProxy(disp_runner_); 178 frames_ = new FrameConsumerProxy(display_task_runner_);
206 // TODO(solb) Instantiate some FrameConsumer implementation and attach it. 179 // TODO(solb) Instantiate some FrameConsumer implementation and attach it.
207 } 180 }
208 181
209 // We're a singleton, so Unretained is safe here. 182 // We're a singleton, so Unretained is safe here.
210 net_runner_->PostTask(FROM_HERE, base::Bind( 183 network_task_runner_->PostTask(FROM_HERE, base::Bind(
211 &ChromotingJNIInstance::ConnectToHostOnNetworkThread, 184 &ChromotingJNIInstance::ConnectToHostOnNetworkThread,
212 base::Unretained(this))); 185 base::Unretained(this)));
213 } 186 }
214 187
215 void ChromotingJNIInstance::ConnectToHostOnNetworkThread() { 188 void ChromotingJNIInstance::ConnectToHostOnNetworkThread() {
216 DCHECK(net_runner_->BelongsToCurrentThread()); 189 DCHECK(network_task_runner_->BelongsToCurrentThread());
217 190
218 client_config_.reset(new ClientConfig()); 191 client_config_.reset(new ClientConfig());
219 client_config_->host_jid = host_jid_cstr_; 192 client_config_->host_jid = host_jid_;
220 client_config_->host_public_key = host_pubkey_cstr_; 193 client_config_->host_public_key = host_pubkey_;
221 // We're a singleton, so Unretained is safe here. 194 // We're a singleton, so Unretained is safe here.
Wez 2013/07/11 22:32:08 nit: Blank line before this comment.
solb 2013/07/11 23:59:09 Done.
222 client_config_->fetch_secret_callback = base::Bind( 195 client_config_->fetch_secret_callback = base::Bind(
223 &ChromotingJNIInstance::FetchSecret, 196 &ChromotingJNIInstance::FetchSecret,
224 base::Unretained(this)); 197 base::Unretained(this));
225 client_config_->authentication_tag = host_id_cstr_; 198 client_config_->authentication_tag = host_id_;
226 199
227 // TODO(solb) Move these hardcoded values elsewhere: 200 // TODO(solb) Move these hardcoded values elsewhere:
228 client_config_->authentication_methods.push_back( 201 client_config_->authentication_methods.push_back(
229 protocol::AuthenticationMethod::FromString("spake2_pair")); 202 protocol::AuthenticationMethod::FromString("spake2_pair"));
230 client_config_->authentication_methods.push_back( 203 client_config_->authentication_methods.push_back(
231 protocol::AuthenticationMethod::FromString("spake2_hmac")); 204 protocol::AuthenticationMethod::FromString("spake2_hmac"));
232 client_config_->authentication_methods.push_back( 205 client_config_->authentication_methods.push_back(
233 protocol::AuthenticationMethod::FromString("spake2_plain")); 206 protocol::AuthenticationMethod::FromString("spake2_plain"));
234 207
235 client_context_.reset(new ClientContext(net_runner_.get())); 208 client_context_.reset(new ClientContext(network_task_runner_.get()));
236 client_context_->Start(); 209 client_context_->Start();
237 210
238 connection_.reset(new protocol::ConnectionToHost(true)); 211 connection_.reset(new protocol::ConnectionToHost(true));
239 212
240 client_.reset(new ChromotingClient(*client_config_, 213 client_.reset(new ChromotingClient(*client_config_,
241 client_context_.get(), 214 client_context_.get(),
242 connection_.get(), 215 connection_.get(),
243 this, 216 this,
244 frames_, 217 frames_,
245 scoped_ptr<AudioPlayer>())); 218 scoped_ptr<AudioPlayer>()));
246 219
247 chat_config_.reset(new XmppSignalStrategy::XmppServerConfig()); 220 chat_config_.reset(new XmppSignalStrategy::XmppServerConfig());
248 chat_config_->host = CHAT_SERVER; 221 chat_config_->host = CHAT_SERVER;
249 chat_config_->port = CHAT_PORT; 222 chat_config_->port = CHAT_PORT;
250 chat_config_->use_tls = CHAT_USE_TLS; 223 chat_config_->use_tls = CHAT_USE_TLS;
251 224
252 chat_.reset(new XmppSignalStrategy(url_requester_, 225 chat_.reset(new XmppSignalStrategy(url_requester_,
253 username_cstr_, 226 username_,
254 auth_token_cstr_, 227 auth_token_,
255 CHAT_AUTH_METHOD, 228 CHAT_AUTH_METHOD,
256 *chat_config_)); 229 *chat_config_));
257 230
258 netset_.reset(new NetworkSettings(NetworkSettings::NAT_TRAVERSAL_OUTGOING)); 231 netset_.reset(new NetworkSettings(NetworkSettings::NAT_TRAVERSAL_OUTGOING));
259 scoped_ptr<protocol::TransportFactory> fact( 232 scoped_ptr<protocol::TransportFactory> fact(
260 protocol::LibjingleTransportFactory::Create(*netset_, url_requester_)); 233 protocol::LibjingleTransportFactory::Create(*netset_, url_requester_));
261 234
262 client_->Start(chat_.get(), fact.Pass()); 235 client_->Start(chat_.get(), fact.Pass());
263 } 236 }
264 237
265 void ChromotingJNIInstance::DisconnectFromHostOnNetworkThread() {
266 DCHECK(net_runner_->BelongsToCurrentThread());
267
268 client_.reset();
269 connection_.reset();
270 client_context_.reset();
271 client_config_.reset();
272 chat_.reset(); // This object must outlive client_.
273 chat_config_.reset(); // TODO(solb) Restructure to reuse between sessions.
274 netset_.reset();
275 }
276
277 } // namespace remoting 238 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698