From 9be2c6d3c2e0c8d80d5b515c641d1c3aa499ec3e Mon Sep 17 00:00:00 2001 From: David Stevens Date: Thu, 12 Nov 2020 18:20:52 +0900 Subject: [PATCH] devices/video/decoder: fix drain+clear queue issue Drain is cancelled by clearing either of the stream's queues. To work around a limitation in the VDA api, the output queue is cleared synchronously without going through VDA. Because of this, a drain cancellation response from VDA might fail to find the drain's AsyncCmdTag. BUG=b:170184723 TEST=android.mediastress.cts.MediaRecorderStressTest#testStressRecordVideoAndPlayback Change-Id: I1d54c9c4acfa7578addb947e1196313010a8431d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2535964 Reviewed-by: Chih-Yu Huang Reviewed-by: Alexandre Courbot Tested-by: kokoro Commit-Queue: David Stevens --- devices/src/virtio/video/worker.rs | 36 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/devices/src/virtio/video/worker.rs b/devices/src/virtio/video/worker.rs index 8911bd5a73..0bac2fcb86 100644 --- a/devices/src/virtio/video/worker.rs +++ b/devices/src/virtio/video/worker.rs @@ -6,7 +6,7 @@ use std::collections::VecDeque; -use base::{error, Event, WaitContext}; +use base::{error, info, Event, WaitContext}; use vm_memory::GuestMemory; use crate::virtio::queue::{DescriptorChain, Queue}; @@ -14,7 +14,7 @@ use crate::virtio::resource_bridge::ResourceRequestSocket; use crate::virtio::video::async_cmd_desc_map::AsyncCmdDescMap; use crate::virtio::video::command::{QueueType, VideoCmd}; use crate::virtio::video::device::{ - AsyncCmdResponse, Device, Token, VideoCmdResponseType, VideoEvtResponseType, + AsyncCmdResponse, AsyncCmdTag, Device, Token, VideoCmdResponseType, VideoEvtResponseType, }; use crate::virtio::video::event::{self, EvtType, VideoEvt}; use crate::virtio::video::response::{self, Response}; @@ -187,17 +187,29 @@ impl Worker { tag, response: cmd_result, } = async_response; - let desc = desc_map - .remove(&tag) - .ok_or_else(|| Error::UnexpectedResponse(tag))?; - let cmd_response = match cmd_result { - Ok(r) => r, - Err(e) => { - error!("returning async error response: {}", &e); - e.into() + match desc_map.remove(&tag) { + Some(desc) => { + let cmd_response = match cmd_result { + Ok(r) => r, + Err(e) => { + error!("returning async error response: {}", &e); + e.into() + } + }; + responses.push_back((desc, cmd_response)) } - }; - responses.push_back((desc, cmd_response)); + None => match tag { + // TODO(b/153406792): Drain is cancelled by clearing either of the + // stream's queues. To work around a limitation in the VDA api, the + // output queue is cleared synchronously without going through VDA. + // Because of this, the cancellation response from VDA for the + // input queue might fail to find the drain's AsyncCmdTag. + AsyncCmdTag::Drain { stream_id: _ } => { + info!("ignoring unknown drain response"); + } + _ => return Err(Error::UnexpectedResponse(tag)), + }, + } } VideoEvtResponseType::Event(evt) => { self.write_event(event_queue, evt)?;