Defer AudioTrack initialization to first ref
Part of AudioTrack initialization involves sharing sp<> based
refs to itself. If this initialization occurs during construction,
races leading to pre-mature destruction and use after free errors
are possible since sp<> creation requires a fully created object.
Push this initialization (calling set) to onFirstRef.
Test: atest AudioTrackTest
Bug: 221393500
Change-Id: Ie28162ec4a975206cb81d13ec3afa930fbd1675c
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index bceca2d..58c4a07 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -277,10 +277,12 @@
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
- (void)set(streamType, sampleRate, format, channelMask,
- frameCount, flags, callback, notificationFrames,
- 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
- attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
+ // make_unique does not aggregate init until c++20
+ mSetParams = std::unique_ptr<SetParams>{
+ new SetParams{streamType, sampleRate, format, channelMask, frameCount, flags, callback,
+ notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/,
+ sessionId, transferType, offloadInfo, attributionSource, pAttributes,
+ doNotReconnect, maxRequiredSpeed, selectedDeviceId}};
}
namespace {
@@ -355,10 +357,11 @@
} else if (user) {
LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
}
- (void)set(streamType, sampleRate, format, channelMask,
- frameCount, flags, mLegacyCallbackWrapper, notificationFrames,
- 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
- attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
+ mSetParams = std::unique_ptr<SetParams>{new SetParams{
+ streamType, sampleRate, format, channelMask, frameCount, flags, mLegacyCallbackWrapper,
+ notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId,
+ transferType, offloadInfo, attributionSource, pAttributes, doNotReconnect,
+ maxRequiredSpeed, selectedDeviceId}};
}
AudioTrack::AudioTrack(
@@ -387,10 +390,11 @@
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
- (void)set(streamType, sampleRate, format, channelMask,
- 0 /*frameCount*/, flags, callback, notificationFrames,
- sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
- attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed);
+ mSetParams = std::unique_ptr<SetParams>{
+ new SetParams{streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags,
+ callback, notificationFrames, sharedBuffer, false /*threadCanCallJava*/,
+ sessionId, transferType, offloadInfo, attributionSource, pAttributes,
+ doNotReconnect, maxRequiredSpeed, AUDIO_PORT_HANDLE_NONE}};
}
AudioTrack::AudioTrack(
@@ -424,11 +428,18 @@
} else if (user) {
LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
}
+ mSetParams = std::unique_ptr<SetParams>{new SetParams{
+ streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags,
+ mLegacyCallbackWrapper, notificationFrames, sharedBuffer, false /*threadCanCallJava*/,
+ sessionId, transferType, offloadInfo, attributionSource, pAttributes, doNotReconnect,
+ maxRequiredSpeed, AUDIO_PORT_HANDLE_NONE}};
+}
- (void)set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags,
- mLegacyCallbackWrapper, notificationFrames, sharedBuffer,
- false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, attributionSource,
- pAttributes, doNotReconnect, maxRequiredSpeed);
+void AudioTrack::onFirstRef() {
+ if (mSetParams) {
+ set(*mSetParams);
+ mSetParams.reset();
+ }
}
AudioTrack::~AudioTrack()
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 1708cc7..1cf6ef9 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -458,6 +458,38 @@
float maxRequiredSpeed = 1.0f,
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+ struct SetParams {
+ audio_stream_type_t streamType;
+ uint32_t sampleRate;
+ audio_format_t format;
+ audio_channel_mask_t channelMask;
+ size_t frameCount;
+ audio_output_flags_t flags;
+ wp<IAudioTrackCallback> callback;
+ int32_t notificationFrames;
+ sp<IMemory> sharedBuffer;
+ bool threadCanCallJava;
+ audio_session_t sessionId;
+ transfer_type transferType;
+ // TODO don't take pointers here
+ const audio_offload_info_t *offloadInfo;
+ AttributionSourceState attributionSource;
+ const audio_attributes_t* pAttributes;
+ bool doNotReconnect;
+ float maxRequiredSpeed;
+ audio_port_handle_t selectedDeviceId;
+ };
+ private:
+ // Note: Consumes parameters
+ void set(SetParams& s) {
+ (void)set(s.streamType, s.sampleRate, s.format, s.channelMask, s.frameCount,
+ s.flags, std::move(s.callback), s.notificationFrames,
+ std::move(s.sharedBuffer), s.threadCanCallJava, s.sessionId,
+ s.transferType, s.offloadInfo, std::move(s.attributionSource),
+ s.pAttributes, s.doNotReconnect, s.maxRequiredSpeed, s.selectedDeviceId);
+ }
+ void onFirstRef() override;
+ public:
status_t set(audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
@@ -1349,6 +1381,8 @@
wp<IAudioTrackCallback> mCallback; // callback handler for events, or NULL
sp<IAudioTrackCallback> mLegacyCallbackWrapper; // wrapper for legacy callback interface
// for notification APIs
+ std::unique_ptr<SetParams> mSetParams; // Temporary copy of ctor params to allow for
+ // deferred set after first reference.
bool mInitialized = false; // Set after track is initialized
// next 2 fields are const after constructor or set()