Merge changes from topic "upstream-close-fixes" am: 7663233f5c am: b6d82825e0

am: 88e9203701

Change-Id: If85dd058799aede5b0770e52b0185d3405f44269
This commit is contained in:
Mikhail Naganov 2019-11-25 07:40:37 -08:00 committed by android-build-merger
commit e74d8746cf
4 changed files with 59 additions and 2 deletions

View file

@ -286,8 +286,12 @@ interface IDevice {
* all currently allocated resources. It is recommended to close
* the device on the client side as soon as it is becomes unused.
*
* Note that all streams must be closed by the client before
* attempting to close the device they belong to.
*
* @return retval OK in case the success.
* INVALID_STATE if the device was already closed.
* INVALID_STATE if the device was already closed
* or there are streams currently opened.
*/
@exit
close() generates (Result retval);

View file

@ -53,10 +53,14 @@ Result Device::analyzeStatus(const char* funcName, int status,
void Device::closeInputStream(audio_stream_in_t* stream) {
mDevice->close_input_stream(mDevice, stream);
LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
--mOpenedStreamsCount;
}
void Device::closeOutputStream(audio_stream_out_t* stream) {
mDevice->close_output_stream(mDevice, stream);
LOG_ALWAYS_FATAL_IF(mOpenedStreamsCount == 0, "mOpenedStreamsCount is already 0");
--mOpenedStreamsCount;
}
char* Device::halGetParameters(const char* keys) {
@ -158,6 +162,7 @@ std::tuple<Result, sp<IStreamOut>> Device::openOutputStreamImpl(int32_t ioHandle
sp<IStreamOut> streamOut;
if (status == OK) {
streamOut = new StreamOut(this, halStream);
++mOpenedStreamsCount;
}
HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut};
@ -184,6 +189,7 @@ std::tuple<Result, sp<IStreamIn>> Device::openInputStreamImpl(
sp<IStreamIn> streamIn;
if (status == OK) {
streamIn = new StreamIn(this, halStream);
++mOpenedStreamsCount;
}
HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
return {analyzeStatus("open_input_stream", status, {EINVAL} /*ignore*/), streamIn};
@ -383,7 +389,7 @@ Return<Result> Device::setConnectedState(const DeviceAddress& address, bool conn
#endif
Result Device::doClose() {
if (mIsClosed) return Result::INVALID_STATE;
if (mIsClosed || mOpenedStreamsCount != 0) return Result::INVALID_STATE;
mIsClosed = true;
return analyzeStatus("close", audio_hw_device_close(mDevice));
}

View file

@ -130,6 +130,7 @@ struct Device : public IDevice, public ParametersUtil {
private:
bool mIsClosed;
audio_hw_device_t* mDevice;
int mOpenedStreamsCount = 0;
virtual ~Device();

View file

@ -145,3 +145,49 @@ const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
}();
return parameters;
}
TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
doc::test("Verify that a device can't be closed if there are streams opened");
DeviceAddress address{.device = AudioDevice::OUT_DEFAULT};
AudioConfig config{};
auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
sp<IStreamOut> stream;
StreamHelper<IStreamOut> helper(stream);
AudioConfig suggestedConfig{};
ASSERT_NO_FATAL_FAILURE(helper.open(
[&](AudioIoHandle handle, AudioConfig config, auto cb) {
return getDevice()->openOutputStream(handle, address, config, flags, initMetadata,
cb);
},
config, &res, &suggestedConfig));
ASSERT_RESULT(Result::INVALID_STATE, getDevice()->close());
ASSERT_NO_FATAL_FAILURE(helper.close(true /*clear*/, &res));
ASSERT_OK(getDevice()->close());
ASSERT_TRUE(resetDevice());
}
TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
doc::test("Verify that a device can't be closed if there are streams opened");
auto module = getCachedPolicyConfig().getModuleFromName(getDeviceName());
if (module->getInputProfiles().empty()) {
GTEST_SKIP() << "Device doesn't have input profiles";
}
DeviceAddress address{.device = AudioDevice::IN_DEFAULT};
AudioConfig config{};
auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
sp<IStreamIn> stream;
StreamHelper<IStreamIn> helper(stream);
AudioConfig suggestedConfig{};
ASSERT_NO_FATAL_FAILURE(helper.open(
[&](AudioIoHandle handle, AudioConfig config, auto cb) {
return getDevice()->openInputStream(handle, address, config, flags, initMetadata,
cb);
},
config, &res, &suggestedConfig));
ASSERT_RESULT(Result::INVALID_STATE, getDevice()->close());
ASSERT_NO_FATAL_FAILURE(helper.close(true /*clear*/, &res));
ASSERT_OK(getDevice()->close());
ASSERT_TRUE(resetDevice());
}