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

Side by Side Diff: content/browser/presentation/presentation_service_impl.cc

Issue 979413002: [Presentation API] Additional plumbing for PresentationServiceImpl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@REAL-NEW-MASTER
Patch Set: Added handling for overlapping requests, default presentation id, 1-UA fallback Created 5 years, 9 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "content/browser/presentation/presentation_service_impl.h" 5 #include "content/browser/presentation/presentation_service_impl.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "content/browser/presentation/presentation_type_converters.h"
8 #include "content/public/browser/content_browser_client.h" 9 #include "content/public/browser/content_browser_client.h"
9 #include "content/public/browser/navigation_details.h" 10 #include "content/public/browser/navigation_details.h"
10 #include "content/public/browser/render_frame_host.h" 11 #include "content/public/browser/render_frame_host.h"
11 #include "content/public/browser/render_process_host.h" 12 #include "content/public/browser/render_process_host.h"
12 #include "content/public/browser/web_contents.h" 13 #include "content/public/browser/web_contents.h"
13 #include "content/public/common/content_client.h" 14 #include "content/public/common/content_client.h"
14 #include "content/public/common/frame_navigate_params.h" 15 #include "content/public/common/frame_navigate_params.h"
15 16
16 namespace content { 17 namespace content {
17 18
18 PresentationServiceImpl::PresentationServiceImpl( 19 PresentationServiceImpl::PresentationServiceImpl(
19 RenderFrameHost* render_frame_host, 20 RenderFrameHost* render_frame_host,
20 WebContents* web_contents, 21 WebContents* web_contents,
21 PresentationServiceDelegate* delegate) 22 PresentationServiceDelegate* delegate)
22 : WebContentsObserver(web_contents), 23 : WebContentsObserver(web_contents),
23 render_frame_host_(render_frame_host), 24 render_frame_host_(render_frame_host),
24 delegate_(delegate) { 25 delegate_(delegate),
26 start_session_in_progress_(false),
27 weak_factory_(this) {
25 DCHECK(render_frame_host_); 28 DCHECK(render_frame_host_);
26 DCHECK(web_contents); 29 DCHECK(web_contents);
27 VLOG(2) << "PresentationServiceImpl: " 30 DVLOG(2) << "PresentationServiceImpl: "
28 << render_frame_host_->GetProcess()->GetID() << ", " 31 << render_frame_host_->GetProcess()->GetID() << ", "
mark a. foltz 2015/03/13 01:39:13 Indentation of this line and the one following nee
imcheng 2015/03/13 23:36:46 Done.
29 << render_frame_host_->GetRoutingID(); 32 << render_frame_host_->GetRoutingID();
30 if (delegate_) 33 if (delegate_)
31 delegate_->AddObserver(this); 34 delegate_->AddObserver(this);
32 } 35 }
33 36
34 PresentationServiceImpl::~PresentationServiceImpl() { 37 PresentationServiceImpl::~PresentationServiceImpl() {
35 if (delegate_) 38 if (delegate_)
36 delegate_->RemoveObserver(this); 39 delegate_->RemoveObserver(this);
37 } 40 }
38 41
39 // static 42 // static
40 void PresentationServiceImpl::CreateMojoService( 43 void PresentationServiceImpl::CreateMojoService(
41 RenderFrameHost* render_frame_host, 44 RenderFrameHost* render_frame_host,
42 mojo::InterfaceRequest<presentation::PresentationService> request) { 45 mojo::InterfaceRequest<presentation::PresentationService> request) {
43 VLOG(2) << "PresentationServiceImpl::CreateService"; 46 DVLOG(2) << "CreateMojoService";
44 WebContents* web_contents = 47 WebContents* web_contents =
45 WebContents::FromRenderFrameHost(render_frame_host); 48 WebContents::FromRenderFrameHost(render_frame_host);
46 DCHECK(web_contents); 49 DCHECK(web_contents);
47 50
48 mojo::BindToRequest( 51 mojo::BindToRequest(
49 new PresentationServiceImpl( 52 new PresentationServiceImpl(
50 render_frame_host, 53 render_frame_host,
51 web_contents, 54 web_contents,
52 GetContentClient()->browser()->GetPresentationServiceDelegate( 55 GetContentClient()->browser()->GetPresentationServiceDelegate(
53 web_contents)), 56 web_contents)),
54 &request); 57 &request);
55 } 58 }
56 59
57 void PresentationServiceImpl::OnConnectionError() { 60 void PresentationServiceImpl::OnConnectionError() {
58 VLOG(1) << "PresentationServiceImpl::OnConnectionError: " 61 DVLOG(1) << "OnConnectionError: "
59 << render_frame_host_->GetProcess()->GetID() << ", " 62 << render_frame_host_->GetProcess()->GetID() << ", "
mark a. foltz 2015/03/13 01:39:13 Indentation
imcheng 2015/03/13 23:36:46 Done.
60 << render_frame_host_->GetRoutingID(); 63 << render_frame_host_->GetRoutingID();
61 } 64 }
62 65
63 void PresentationServiceImpl::GetScreenAvailability( 66 void PresentationServiceImpl::GetScreenAvailability(
64 const mojo::String& presentation_url, 67 const mojo::String& presentation_url,
65 const ScreenAvailabilityMojoCallback& callback) { 68 const ScreenAvailabilityMojoCallback& callback) {
66 VLOG(2) << "PresentationServiceImpl::GetScreenAvailability"; 69 DVLOG(2) << "GetScreenAvailability";
67 if (!delegate_) 70 if (!delegate_)
68 return; 71 return;
69 72
70 const std::string& presentation_url_str = !presentation_url.is_null() ? 73 const std::string& presentation_url_str = presentation_url.get();
71 presentation_url.get() : default_presentation_url_;
72
73 // GetScreenAvailability() is called with no URL and there is no default
74 // Presentation URL.
75 if (presentation_url_str.empty())
76 return;
77
78 auto it = availability_contexts_.find(presentation_url_str); 74 auto it = availability_contexts_.find(presentation_url_str);
mark a. foltz 2015/03/13 01:39:13 Can you factor out a method GetOrCreaeteAvailabilt
imcheng 2015/03/13 23:36:46 Done.
79 if (it == availability_contexts_.end()) { 75 if (it == availability_contexts_.end()) {
80 linked_ptr<ScreenAvailabilityContext> context( 76 linked_ptr<ScreenAvailabilityContext> context(
81 new ScreenAvailabilityContext(presentation_url_str)); 77 new ScreenAvailabilityContext(presentation_url_str));
82
83 if (!delegate_->AddScreenAvailabilityListener( 78 if (!delegate_->AddScreenAvailabilityListener(
84 render_frame_host_->GetProcess()->GetID(), 79 render_frame_host_->GetProcess()->GetID(),
85 render_frame_host_->GetRoutingID(), 80 render_frame_host_->GetRoutingID(),
86 context.get())) { 81 context.get())) {
87 VLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request."; 82 DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
88 return; 83 return;
89 } 84 }
90
91 it = availability_contexts_.insert( 85 it = availability_contexts_.insert(
92 std::make_pair(presentation_url_str, context)).first; 86 std::make_pair(context->GetPresentationUrl(), context)).first;
93 } 87 }
94
95 it->second->CallbackReceived(callback); 88 it->second->CallbackReceived(callback);
96 } 89 }
97 90
98 void PresentationServiceImpl::OnScreenAvailabilityListenerRemoved() { 91 void PresentationServiceImpl::OnScreenAvailabilityListenerRemoved(
99 NOTIMPLEMENTED(); 92 const mojo::String& presentation_url) {
93 DVLOG(2) << "OnScreenAvailabilityListenerRemoved";
94 if (!delegate_)
95 return;
96
97 const std::string& presentation_url_str = presentation_url.get();
98 auto it = availability_contexts_.find(presentation_url_str);
mark a. foltz 2015/03/13 01:39:13 Factor out method GetAvailabilityContext(str)?
imcheng 2015/03/13 23:36:46 Actually, I need the iterator here since erase by
99 if (it == availability_contexts_.end())
100 return;
101
102 delegate_->RemoveScreenAvailabilityListener(
mark a. foltz 2015/03/13 01:39:13 Is the delegate_ unique to this instance of the Pr
imcheng 2015/03/13 23:36:46 It is not. It's actually per tab (see line 55-56)
103 render_frame_host_->GetProcess()->GetID(),
104 render_frame_host_->GetRoutingID(),
105 it->second.get());
106 availability_contexts_.erase(it);
100 } 107 }
101 108
102 void PresentationServiceImpl::StartSession( 109 void PresentationServiceImpl::StartSession(
103 const mojo::String& presentation_url, 110 const mojo::String& presentation_url,
104 const mojo::String& presentation_id, 111 const mojo::String& presentation_id,
105 const NewSessionMojoCallback& callback) { 112 const NewSessionMojoCallback& callback) {
106 NOTIMPLEMENTED(); 113 DVLOG(2) << "StartSession";
114 if (!delegate_)
115 return;
116
117 if (!start_session_in_progress_) {
mark a. foltz 2015/03/13 01:39:12 Is this test the same as queued_start_session_requ
whywhat 2015/03/13 17:44:35 I think one can have one session being started whi
imcheng 2015/03/13 23:36:46 Ok, I will make the change as you suggest to get r
118 DoStartSession(presentation_url, presentation_id, callback);
119 } else {
120 queued_start_session_requests_.push_back(make_linked_ptr(
121 new StartSessionRequest(presentation_url, presentation_id, callback)));
122 }
107 } 123 }
108 124
109 void PresentationServiceImpl::JoinSession( 125 void PresentationServiceImpl::JoinSession(
110 const mojo::String& presentation_url, 126 const mojo::String& presentation_url,
111 const mojo::String& presentation_id, 127 const mojo::String& presentation_id,
112 const NewSessionMojoCallback& callback) { 128 const NewSessionMojoCallback& callback) {
113 NOTIMPLEMENTED(); 129 DVLOG(2) << "JoinSession";
130 if (!delegate_)
131 return;
132
133 delegate_->JoinSession(
134 render_frame_host_->GetProcess()->GetID(),
135 render_frame_host_->GetRoutingID(),
136 presentation_url,
137 presentation_id,
138 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
139 weak_factory_.GetWeakPtr(), false, callback),
140 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
141 weak_factory_.GetWeakPtr(), false, callback));
142 }
143
144 void PresentationServiceImpl::HandleQueuedStartSessionRequests() {
145 if (queued_start_session_requests_.empty()) {
mark a. foltz 2015/03/13 01:39:13 Ditto
imcheng 2015/03/13 23:36:46 It wasn't the same because there could be a reques
146 start_session_in_progress_ = false;
147 } else {
148 linked_ptr<StartSessionRequest> request =
149 queued_start_session_requests_.front();
150 queued_start_session_requests_.pop_front();
151 DoStartSession(request->presentation_url,
152 request->presentation_id,
153 request->callback);
154 }
155 }
156
157 void PresentationServiceImpl::DoStartSession(
158 const std::string& presentation_url,
159 const std::string& presentation_id,
160 const NewSessionMojoCallback& callback) {
161 start_session_in_progress_ = true;
whywhat 2015/03/13 17:44:35 if called from HandleQueueStartSessionRequests, it
imcheng 2015/03/13 23:36:46 Yes.
162 delegate_->StartSession(
163 render_frame_host_->GetProcess()->GetID(),
164 render_frame_host_->GetRoutingID(),
165 presentation_url,
166 presentation_id,
167 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
168 weak_factory_.GetWeakPtr(), true, callback),
169 base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
170 weak_factory_.GetWeakPtr(), true, callback));
171 }
172
173 void PresentationServiceImpl::OnStartOrJoinSessionSucceeded(
174 bool is_start_session,
175 const NewSessionMojoCallback& callback,
176 const PresentationSessionInfo& session_info) {
177 callback.Run(
178 presentation::PresentationSessionInfo::From(session_info),
179 presentation::PresentationErrorPtr());
180 if (is_start_session) {
whywhat 2015/03/13 17:44:35 No need for braces for one line if branches.
imcheng 2015/03/13 23:36:46 Done.
181 HandleQueuedStartSessionRequests();
182 }
183 }
184
185 void PresentationServiceImpl::OnStartOrJoinSessionError(
186 bool is_start_session,
187 const NewSessionMojoCallback& callback,
188 const PresentationError& error) {
189 callback.Run(
190 presentation::PresentationSessionInfoPtr(),
191 presentation::PresentationError::From(error));
192 if (is_start_session) {
193 HandleQueuedStartSessionRequests();
whywhat 2015/03/13 17:44:35 ditto
imcheng 2015/03/13 23:36:46 Done.
194 }
195 }
196
197 void PresentationServiceImpl::DoSetDefaultPresentationUrl(
198 const std::string& default_presentation_url,
199 const std::string& default_presentation_id) {
200 DCHECK(delegate_);
201 delegate_->SetDefaultPresentationUrl(
202 render_frame_host_->GetProcess()->GetID(),
203 render_frame_host_->GetRoutingID(),
204 default_presentation_url,
205 default_presentation_id);
206 default_presentation_url_ = default_presentation_url;
207 default_presentation_id_ = default_presentation_id;
208 }
209
210 void PresentationServiceImpl::SetDefaultPresentationUrl(
211 const mojo::String& default_presentation_url,
212 const mojo::String& default_presentation_id) {
213 DVLOG(2) << "SetDefaultPresentationUrl";
214 if (!delegate_)
215 return;
216
217 std::string old_default_url(default_presentation_url_);
mark a. foltz 2015/03/13 01:39:13 const std::string& ... .get() like you did above?
imcheng 2015/03/13 23:36:46 Done.
218 std::string new_default_url(default_presentation_url);
219
220 // Don't call delegate if nothing changed.
221 if (old_default_url == new_default_url &&
222 default_presentation_id_ == default_presentation_id) {
223 return;
224 }
225
226 auto old_it = availability_contexts_.find(old_default_url);
227 // Haven't started listening yet.
228 if (old_it == availability_contexts_.end()) {
229 DoSetDefaultPresentationUrl(new_default_url, default_presentation_id);
230 return;
231 }
232
233 // Have already started listening. Create a listener for the new URL and
234 // transfer the callback from the old listener, if any.
235 // This is done so that a listener added before default URL is changed
236 // will continue to work.
237 ScreenAvailabilityMojoCallback* old_callback = old_it->second->callback();
238 auto new_it = availability_contexts_.find(new_default_url);
239 if (new_it == availability_contexts_.end()) {
240 linked_ptr<ScreenAvailabilityContext> context(
241 new ScreenAvailabilityContext(new_default_url));
242 if (!delegate_->AddScreenAvailabilityListener(
243 render_frame_host_->GetProcess()->GetID(),
244 render_frame_host_->GetRoutingID(),
245 context.get())) {
246 DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
247 return;
248 }
249 new_it = availability_contexts_.insert(
250 std::make_pair(context->GetPresentationUrl(), context)).first;
mark a. foltz 2015/03/13 01:39:13 The method I suggested above to get or create the
imcheng 2015/03/13 23:36:46 Done.
251 }
252 if (old_callback)
253 new_it->second->CallbackReceived(*old_callback);
254
255 // Remove listener for old default presentation URL.
256 delegate_->RemoveScreenAvailabilityListener(
257 render_frame_host_->GetProcess()->GetID(),
258 render_frame_host_->GetRoutingID(),
259 old_it->second.get());
260 availability_contexts_.erase(old_it);
261 DoSetDefaultPresentationUrl(new_default_url, default_presentation_id);
114 } 262 }
115 263
116 void PresentationServiceImpl::DidNavigateAnyFrame( 264 void PresentationServiceImpl::DidNavigateAnyFrame(
117 content::RenderFrameHost* render_frame_host, 265 content::RenderFrameHost* render_frame_host,
118 const content::LoadCommittedDetails& details, 266 const content::LoadCommittedDetails& details,
119 const content::FrameNavigateParams& params) { 267 const content::FrameNavigateParams& params) {
120 VLOG(2) << "PresentationServiceImpl::DidNavigateAnyFrame"; 268 DVLOG(2) << "PresentationServiceImpl::DidNavigateAnyFrame";
121 if (render_frame_host_ != render_frame_host) 269 if (render_frame_host_ != render_frame_host)
122 return; 270 return;
123 271
124 std::string prev_url_host = details.previous_url.host(); 272 std::string prev_url_host = details.previous_url.host();
125 std::string curr_url_host = params.url.host(); 273 std::string curr_url_host = params.url.host();
126 274
127 // If a frame navigation is in-page (e.g. navigating to a fragment in 275 // If a frame navigation is in-page (e.g. navigating to a fragment in
128 // same page) then we do not unregister listeners. 276 // same page) then we do not unregister listeners.
129 bool in_page_navigation = details.is_in_page || 277 bool in_page_navigation = details.is_in_page ||
130 details.type == content::NAVIGATION_TYPE_IN_PAGE; 278 details.type == content::NAVIGATION_TYPE_IN_PAGE;
131 279
132 VLOG(2) << "DidNavigateAnyFrame: " 280 DVLOG(2) << "DidNavigateAnyFrame: "
133 << "prev host: " << prev_url_host << ", curr host: " << curr_url_host 281 << "prev host: " << prev_url_host << ", curr host: " << curr_url_host
134 << ", in_page_navigation: " << in_page_navigation; 282 << ", in_page_navigation: " << in_page_navigation;
135 283
136 if (in_page_navigation) 284 if (in_page_navigation)
137 return; 285 return;
138 286
139 // Unregister all sources if the frame actually navigated. 287 // Reset if the frame actually navigated.
140 RemoveAllListeners(); 288 Reset();
141 } 289 }
142 290
143 void PresentationServiceImpl::RenderFrameDeleted( 291 void PresentationServiceImpl::RenderFrameDeleted(
144 content::RenderFrameHost* render_frame_host) { 292 content::RenderFrameHost* render_frame_host) {
145 VLOG(2) << "PresentationServiceImpl::RenderFrameDeleted"; 293 DVLOG(2) << "PresentationServiceImpl::RenderFrameDeleted";
146 if (render_frame_host_ != render_frame_host) 294 if (render_frame_host_ != render_frame_host)
147 return; 295 return;
148 296
149 // RenderFrameDeleted means this object is getting deleted soon. 297 // RenderFrameDeleted means this object is getting deleted soon.
150 RemoveAllListeners(); 298 Reset();
151 } 299 }
152 300
153 void PresentationServiceImpl::RemoveAllListeners() { 301 void PresentationServiceImpl::Reset() {
154 VLOG(2) << "PresentationServiceImpl::RemoveAllListeners"; 302 DVLOG(2) << "PresentationServiceImpl::Reset";
155 if (!delegate_) 303 if (delegate_) {
156 return; 304 delegate_->RemoveAllScreenAvailabilityListeners(
157
158 delegate_->RemoveAllScreenAvailabilityListeners(
159 render_frame_host_->GetProcess()->GetID(), 305 render_frame_host_->GetProcess()->GetID(),
160 render_frame_host_->GetRoutingID()); 306 render_frame_host_->GetRoutingID());
161 307
308 // Clear default presentation URL.
309 DoSetDefaultPresentationUrl(std::string(), std::string());
310 }
311
162 availability_contexts_.clear(); 312 availability_contexts_.clear();
313 start_session_in_progress_ = false;
314 queued_start_session_requests_.clear();
163 } 315 }
164 316
165 void PresentationServiceImpl::OnDelegateDestroyed() { 317 void PresentationServiceImpl::OnDelegateDestroyed() {
166 VLOG(2) << "PresentationServiceImpl::OnDelegateDestroyed"; 318 DVLOG(2) << "PresentationServiceImpl::OnDelegateDestroyed";
167 delegate_ = nullptr; 319 delegate_ = nullptr;
320 Reset();
168 } 321 }
169 322
170 PresentationServiceImpl::ScreenAvailabilityContext::ScreenAvailabilityContext( 323 PresentationServiceImpl::ScreenAvailabilityContext::ScreenAvailabilityContext(
171 const std::string& presentation_url) 324 const std::string& presentation_url)
172 : presentation_url_(presentation_url) { 325 : presentation_url_(presentation_url) {
173 } 326 }
174 327
175 PresentationServiceImpl::ScreenAvailabilityContext:: 328 PresentationServiceImpl::ScreenAvailabilityContext::
176 ~ScreenAvailabilityContext() { 329 ~ScreenAvailabilityContext() {
177 } 330 }
178 331
179 void PresentationServiceImpl::ScreenAvailabilityContext::CallbackReceived( 332 void PresentationServiceImpl::ScreenAvailabilityContext::CallbackReceived(
180 const ScreenAvailabilityMojoCallback& callback) { 333 const ScreenAvailabilityMojoCallback& callback) {
181 // NOTE: This will overwrite previously registered callback if any. 334 // NOTE: This will overwrite previously registered callback if any.
182 if (!available_ptr_) { 335 if (!available_ptr_) {
183 // No results yet, store callback for later invocation. 336 // No results yet, store callback for later invocation.
184 callback_ptr_.reset(new ScreenAvailabilityMojoCallback(callback)); 337 callback_ptr_.reset(new ScreenAvailabilityMojoCallback(callback));
185 } else { 338 } else {
186 // Run callback now, reset result. 339 // Run callback now, reset result.
187 // There shouldn't be any callbacks stored in this scenario. 340 // There shouldn't be any callbacks stored in this scenario.
188 DCHECK(!callback_ptr_); 341 DCHECK(!callback_ptr_);
189 callback.Run(*available_ptr_); 342 callback.Run(presentation_url_, *available_ptr_);
190 Reset(); 343 Reset();
191 } 344 }
192 } 345 }
193 346
194 void PresentationServiceImpl::ScreenAvailabilityContext::Reset() { 347 void PresentationServiceImpl::ScreenAvailabilityContext::Reset() {
195 callback_ptr_.reset(); 348 callback_ptr_.reset();
196 available_ptr_.reset(); 349 available_ptr_.reset();
197 } 350 }
198 351
199 std::string PresentationServiceImpl::ScreenAvailabilityContext 352 std::string PresentationServiceImpl::ScreenAvailabilityContext
200 ::GetPresentationUrl() const { 353 ::GetPresentationUrl() const {
201 return presentation_url_; 354 return presentation_url_;
202 } 355 }
203 356
204 void PresentationServiceImpl::ScreenAvailabilityContext 357 void PresentationServiceImpl::ScreenAvailabilityContext
205 ::OnScreenAvailabilityChanged(bool available) { 358 ::OnScreenAvailabilityChanged(bool available) {
206 if (!callback_ptr_) { 359 if (!callback_ptr_) {
207 // No callback, stash the result for now. 360 // No callback, stash the result for now.
208 available_ptr_.reset(new bool(available)); 361 available_ptr_.reset(new bool(available));
209 } else { 362 } else {
210 // Invoke callback and erase it. 363 // Invoke callback and erase it.
211 // There shouldn't be any result stored in this scenario. 364 // There shouldn't be any result stored in this scenario.
212 DCHECK(!available_ptr_); 365 DCHECK(!available_ptr_);
213 callback_ptr_->Run(available); 366 callback_ptr_->Run(presentation_url_, available);
214 Reset(); 367 Reset();
215 } 368 }
216 } 369 }
217 370
371 PresentationServiceImpl::StartSessionRequest::StartSessionRequest(
372 const std::string& presentation_url,
373 const std::string& presentation_id,
374 const NewSessionMojoCallback& callback)
375 : presentation_url(presentation_url),
376 presentation_id(presentation_id),
377 callback(callback) {
378 }
379
380 PresentationServiceImpl::StartSessionRequest::~StartSessionRequest() {
381 }
382
218 } // namespace content 383 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698