• David Tseng's avatar
    Fix potential hang in TtsControllerImpl · b34ba0a1
    David Tseng authored
    In the attached bug, speech is triggered in a startup, fresh imaged
    environment.
    
    To replicate this,
    `rm -rf /home/chronos/*`, then trigger some tts after boot.
    
    The browser process hangs, e.g.
    gdb attach <browser_pid>
    ...
    bt
    
    ...
    #5  0x000058e02342da8f in TtsExtensionEngine::GetVoices(content::BrowserContext*, std::__1::vector<content::VoiceData, std::__1::allocator<content::VoiceData> >*) ()
    #6  0x000058e021612615 in content::TtsControllerImpl::SpeakNow(std::__1::unique_ptr<content::TtsUtterance, std::__1::default_delete<content::TtsUtterance> >) ()
    #7  0x000058e021612e8f in content::TtsControllerImpl::SpeakNextUtterance() ()
    #8  0x000058e01ff769d4 in content::TtsControllerImpl::VoicesChanged() ()
    #9  0x000058e02342eeb4 in ExtensionTtsEngineUpdateVoicesFunction::Run() ()
    #10 0x000058e02185ebe2 in ExtensionFunction::RunWithValidation() ()
    #11 0x000058e021860c5d in extensions::ExtensionFunctionDispatcher::DispatchWithCallbackInternal(ExtensionHostMsg_Request_Params const&, content::RenderFrameHost*, int, base::RepeatingCallback<void (ExtensionFunction::ResponseType, base::ListValue const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> const&) ()
    #12 0x000058e021860773 in extensions::ExtensionFunctionDispatcher::Dispatch(ExtensionHostMsg_Request_Params const&, content::RenderFrameHost*, int) ()
    #13 0x000058e0218818ea in bool IPC::MessageT<ExtensionHostMsg_Request_Meta, std::__1::tuple<ExtensionHostMsg_Request_Params>, void>::Dispatch<extensions::ExtensionWebContentsObserver, extensions::ExtensionWebContentsObserver, content::RenderFrameHost, void (extensions::ExtensionWebContentsObserver::*)(content::RenderFrameHost*, ExtensionHostMsg_Request_Params const&)>(IPC::Message const*, extensions::ExtensionWebContentsObserver*, extensions::ExtensionWebContentsObserver*, content::RenderFrameHost*, void (extensions::ExtensionWebContentsObserver::*)(content::RenderFrameHost*, ExtensionHostMsg_Request_Params const&)) ()
    
    The hang:
    TtsControllerImpl::SpeakNextUtterance ->
    TtsControllerImpl::SpeakNow ->
    TtsControllerImpl::OnSpeakFinished ->
    enqueues the utterance back onto |utterance_list_| on failure.
    
    which occurs all while(... !utterance_list_.empty()), leading to a
    browser hang.
    
    Solution:
    The above utterance fails immediately because the voice is not yet
    ready.  We fix this by never returning the voice in the first place, in
    TtsControllerImpl::GetVoices.
    
    Therefore, we never get to the point where an utterance matches against
    a not yet initialized voice, leading to an attempt to speak, then to an
    immediate failure, next to a re-enqueue, and finally a hang.
    
    Bug: 1161107
    Change-Id: I2d88c0c6e86bf79ad9ac5dc5240825848daa40ae
    Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2642746
    Commit-Queue: David Tseng <dtseng@chromium.org>
    Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#845861}
    b34ba0a1
tts_controller_impl.cc 28.3 KB