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

Side by Side Diff: content/browser/renderer_host/media/audio_renderer_host.cc

Issue 2301353007: Fix race in AudioRendererHost around render frame ID validation. (Closed)
Patch Set: Created 4 years, 3 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/renderer_host/media/audio_renderer_host.h" 5 #include "content/browser/renderer_host/media/audio_renderer_host.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 *params = media::AudioParameters::UnavailableDeviceParams(); 108 *params = media::AudioParameters::UnavailableDeviceParams();
109 } 109 }
110 110
111 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) { 111 void UMALogDeviceAuthorizationTime(base::TimeTicks auth_start_time) {
112 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime", 112 UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.OutputDeviceAuthorizationTime",
113 base::TimeTicks::Now() - auth_start_time, 113 base::TimeTicks::Now() - auth_start_time,
114 base::TimeDelta::FromMilliseconds(1), 114 base::TimeDelta::FromMilliseconds(1),
115 base::TimeDelta::FromMilliseconds(5000), 50); 115 base::TimeDelta::FromMilliseconds(5000), 50);
116 } 116 }
117 117
118 #if DCHECK_IS_ON()
119 // Check that the routing ID references a valid RenderFrameHost, and run 118 // Check that the routing ID references a valid RenderFrameHost, and run
120 // |callback| on the IO thread with true if the ID is valid. 119 // |callback| on the IO thread with true if the ID is valid.
121 void ValidateRenderFrameId(int render_process_id, 120 void ValidateRenderFrameId(int render_process_id,
122 int render_frame_id, 121 int render_frame_id,
123 const base::Callback<void(bool)>& callback) { 122 const base::Callback<void(bool)>& callback) {
124 DCHECK_CURRENTLY_ON(BrowserThread::UI); 123 DCHECK_CURRENTLY_ON(BrowserThread::UI);
125 const bool frame_exists = 124 const bool frame_exists =
126 !!RenderFrameHost::FromID(render_process_id, render_frame_id); 125 !!RenderFrameHost::FromID(render_process_id, render_frame_id);
127 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 126 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
128 base::Bind(callback, frame_exists)); 127 base::Bind(callback, frame_exists));
129 } 128 }
130 #endif // DCHECK_IS_ON()
131 129
132 } // namespace 130 } // namespace
133 131
134 class AudioRendererHost::AudioEntry 132 class AudioRendererHost::AudioEntry
135 : public media::AudioOutputController::EventHandler { 133 : public media::AudioOutputController::EventHandler {
136 public: 134 public:
137 AudioEntry(AudioRendererHost* host, 135 AudioEntry(AudioRendererHost* host,
138 int stream_id, 136 int stream_id,
139 int render_frame_id, 137 int render_frame_id,
140 const media::AudioParameters& params, 138 const media::AudioParameters& params,
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 const std::string& salt) 220 const std::string& salt)
223 : BrowserMessageFilter(AudioMsgStart), 221 : BrowserMessageFilter(AudioMsgStart),
224 render_process_id_(render_process_id), 222 render_process_id_(render_process_id),
225 audio_manager_(audio_manager), 223 audio_manager_(audio_manager),
226 mirroring_manager_(mirroring_manager), 224 mirroring_manager_(mirroring_manager),
227 audio_log_(media_internals->CreateAudioLog( 225 audio_log_(media_internals->CreateAudioLog(
228 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), 226 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
229 media_stream_manager_(media_stream_manager), 227 media_stream_manager_(media_stream_manager),
230 num_playing_streams_(0), 228 num_playing_streams_(0),
231 salt_(salt), 229 salt_(salt),
232 #if DCHECK_IS_ON()
233 validate_render_frame_id_function_(&ValidateRenderFrameId), 230 validate_render_frame_id_function_(&ValidateRenderFrameId),
234 #endif // DCHECK_IS_ON()
235 max_simultaneous_streams_(0) { 231 max_simultaneous_streams_(0) {
236 DCHECK(audio_manager_); 232 DCHECK(audio_manager_);
237 DCHECK(media_stream_manager_); 233 DCHECK(media_stream_manager_);
238 } 234 }
239 235
240 AudioRendererHost::~AudioRendererHost() { 236 AudioRendererHost::~AudioRendererHost() {
241 DCHECK_CURRENTLY_ON(BrowserThread::IO); 237 DCHECK_CURRENTLY_ON(BrowserThread::IO);
242 CHECK(audio_entries_.empty()); 238 CHECK(audio_entries_.empty());
243 239
244 // If we had any streams, report UMA stats for the maximum number of 240 // If we had any streams, report UMA stats for the maximum number of
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) { 344 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
349 ReportErrorAndClose(entry->stream_id()); 345 ReportErrorAndClose(entry->stream_id());
350 return; 346 return;
351 } 347 }
352 348
353 Send(new AudioMsg_NotifyStreamCreated( 349 Send(new AudioMsg_NotifyStreamCreated(
354 entry->stream_id(), foreign_memory_handle, socket_descriptor, 350 entry->stream_id(), foreign_memory_handle, socket_descriptor,
355 entry->shared_memory()->requested_size())); 351 entry->shared_memory()->requested_size()));
356 } 352 }
357 353
354 void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) {
355 DCHECK_CURRENTLY_ON(BrowserThread::IO);
356
357 if (!is_valid) {
358 DLOG(WARNING) << "Render frame for stream (id=" << stream_id
359 << ") no longer exists.";
360 ReportErrorAndClose(stream_id);
o1ka 2016/09/05 11:58:38 My concern is that (as far as I understand) this m
DaleCurtis 2016/09/06 19:24:40 If this isn't okay then none of our error handling
361 }
362 }
363
358 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, 364 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
359 bool is_playing) { 365 bool is_playing) {
360 DCHECK_CURRENTLY_ON(BrowserThread::IO); 366 DCHECK_CURRENTLY_ON(BrowserThread::IO);
361 367
362 AudioEntry* const entry = LookupById(stream_id); 368 AudioEntry* const entry = LookupById(stream_id);
363 if (!entry) 369 if (!entry)
364 return; 370 return;
365 371
366 Send(new AudioMsg_NotifyStreamStateChanged( 372 Send(new AudioMsg_NotifyStreamStateChanged(
367 stream_id, 373 stream_id,
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 // empty string (i.e., when no previous authorization was requested, assume 570 // empty string (i.e., when no previous authorization was requested, assume
565 // default device). 571 // default device).
566 std::string device_unique_id; 572 std::string device_unique_id;
567 const auto& auth_data = authorizations_.find(stream_id); 573 const auto& auth_data = authorizations_.find(stream_id);
568 if (auth_data != authorizations_.end()) { 574 if (auth_data != authorizations_.end()) {
569 CHECK(auth_data->second.first); 575 CHECK(auth_data->second.first);
570 device_unique_id.swap(auth_data->second.second); 576 device_unique_id.swap(auth_data->second.second);
571 authorizations_.erase(auth_data); 577 authorizations_.erase(auth_data);
572 } 578 }
573 579
574 #if DCHECK_IS_ON()
575 // When DCHECKs are turned on, hop over to the UI thread to validate the
576 // |render_frame_id|, then continue stream creation on the IO thread. See
577 // comment at top of DoCreateStream() for further details.
578 BrowserThread::PostTask(
579 BrowserThread::UI, FROM_HERE,
580 base::Bind(validate_render_frame_id_function_, render_process_id_,
581 render_frame_id,
582 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id,
583 render_frame_id, params, device_unique_id)));
584 #else
585 DoCreateStream(stream_id, render_frame_id, params, device_unique_id,
586 render_frame_id > 0);
587 #endif // DCHECK_IS_ON()
588 }
589
590 void AudioRendererHost::DoCreateStream(int stream_id,
591 int render_frame_id,
592 const media::AudioParameters& params,
593 const std::string& device_unique_id,
594 bool render_frame_id_is_valid) {
595 DCHECK_CURRENTLY_ON(BrowserThread::IO);
596
597 // Fail early if either of two sanity-checks fail: 580 // Fail early if either of two sanity-checks fail:
598 // 1. There should not yet exist an AudioEntry for the given |stream_id| 581 // 1. There should not yet exist an AudioEntry for the given |stream_id|
599 // since the renderer may not create two streams with the same ID. 582 // since the renderer may not create two streams with the same ID.
600 // 2. The render frame ID was either invalid or the render frame host it 583 // 2. An out-of-range render frame ID was provided. Renderers must *always*
601 // references has shutdown before the request could be fulfilled (race 584 // specify a valid render frame ID for each audio output they create, as
602 // condition). Renderers must *always* specify a valid render frame ID 585 // several browser-level features depend on this (e.g., OOM manager, UI
603 // for each audio output they create, as several browser-level features 586 // audio indicator, muting, audio capture).
604 // depend on this (e.g., OOM manager, UI audio indicator, muting, audio
605 // capture).
606 // Note: media::AudioParameters is validated in the deserializer, so there is 587 // Note: media::AudioParameters is validated in the deserializer, so there is
607 // no need to check that here. 588 // no need to check that here.
608 if (LookupById(stream_id)) { 589 if (LookupById(stream_id)) {
609 SendErrorMessage(stream_id); 590 SendErrorMessage(stream_id);
610 return; 591 return;
611 } 592 }
612 if (!render_frame_id_is_valid) { 593 if (render_frame_id <= 0) {
613 SendErrorMessage(stream_id); 594 SendErrorMessage(stream_id);
614 return; 595 return;
615 } 596 }
616 597
598 // Post a task to the UI thread to check that the |render_frame_id| references
599 // a valid render frame. This validation is important for all the reasons
600 // stated in the comments above. This does not block stream creation, but will
601 // force-close the stream later if validation fails.
602 BrowserThread::PostTask(
603 BrowserThread::UI, FROM_HERE,
604 base::Bind(validate_render_frame_id_function_, render_process_id_,
605 render_frame_id,
606 base::Bind(&AudioRendererHost::DidValidateRenderFrame, this,
607 stream_id)));
608
617 // Create the shared memory and share with the renderer process. 609 // Create the shared memory and share with the renderer process.
618 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + 610 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) +
619 AudioBus::CalculateMemorySize(params); 611 AudioBus::CalculateMemorySize(params);
620 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); 612 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
621 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { 613 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
622 SendErrorMessage(stream_id); 614 SendErrorMessage(stream_id);
623 return; 615 return;
624 } 616 }
625 617
626 std::unique_ptr<AudioSyncReader> reader( 618 std::unique_ptr<AudioSyncReader> reader(
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
861 callback.Run(false, device_info); 853 callback.Run(false, device_info);
862 } 854 }
863 855
864 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { 856 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) {
865 DCHECK_CURRENTLY_ON(BrowserThread::IO); 857 DCHECK_CURRENTLY_ON(BrowserThread::IO);
866 const auto& i = authorizations_.find(stream_id); 858 const auto& i = authorizations_.find(stream_id);
867 return i != authorizations_.end(); 859 return i != authorizations_.end();
868 } 860 }
869 861
870 } // namespace content 862 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698