Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af12f3c9 authored by Atneya Nair's avatar Atneya Nair
Browse files

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
parent b428b009
Loading
Loading
Loading
Loading
+27 −16
Original line number Original line Diff line number Diff line
@@ -277,10 +277,12 @@ AudioTrack::AudioTrack(
{
{
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;


    (void)set(streamType, sampleRate, format, channelMask,
    // make_unique does not aggregate init until c++20
            frameCount, flags, callback, notificationFrames,
    mSetParams = std::unique_ptr<SetParams>{
            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
            new SetParams{streamType, sampleRate, format, channelMask, frameCount, flags, callback,
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
                          notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/,
                          sessionId, transferType, offloadInfo, attributionSource, pAttributes,
                          doNotReconnect, maxRequiredSpeed, selectedDeviceId}};
}
}


namespace {
namespace {
@@ -355,10 +357,11 @@ AudioTrack::AudioTrack(
    } else if (user) {
    } else if (user) {
        LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
        LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
    }
    }
    (void)set(streamType, sampleRate, format, channelMask,
    mSetParams = std::unique_ptr<SetParams>{new SetParams{
            frameCount, flags, mLegacyCallbackWrapper, notificationFrames,
            streamType, sampleRate, format, channelMask, frameCount, flags, mLegacyCallbackWrapper,
            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
            notificationFrames, 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId,
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
            transferType, offloadInfo, attributionSource, pAttributes, doNotReconnect,
            maxRequiredSpeed, selectedDeviceId}};
}
}


AudioTrack::AudioTrack(
AudioTrack::AudioTrack(
@@ -387,10 +390,11 @@ AudioTrack::AudioTrack(
{
{
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
    mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;


    (void)set(streamType, sampleRate, format, channelMask,
    mSetParams = std::unique_ptr<SetParams>{
            0 /*frameCount*/, flags, callback, notificationFrames,
            new SetParams{streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags,
            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
                          callback, notificationFrames, sharedBuffer, false /*threadCanCallJava*/,
            attributionSource, pAttributes, doNotReconnect, maxRequiredSpeed);
                          sessionId, transferType, offloadInfo, attributionSource, pAttributes,
                          doNotReconnect, maxRequiredSpeed, AUDIO_PORT_HANDLE_NONE}};
}
}


AudioTrack::AudioTrack(
AudioTrack::AudioTrack(
@@ -424,11 +428,18 @@ AudioTrack::AudioTrack(
    } else if (user) {
    } else if (user) {
        LOG_ALWAYS_FATAL("Callback data provided without callback pointer!");
        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,
void AudioTrack::onFirstRef() {
              mLegacyCallbackWrapper, notificationFrames, sharedBuffer,
    if (mSetParams) {
              false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, attributionSource,
        set(*mSetParams);
              pAttributes, doNotReconnect, maxRequiredSpeed);
        mSetParams.reset();
    }
}
}


AudioTrack::~AudioTrack()
AudioTrack::~AudioTrack()
+34 −0
Original line number Original line Diff line number Diff line
@@ -458,6 +458,38 @@ public:
                            float maxRequiredSpeed = 1.0f,
                            float maxRequiredSpeed = 1.0f,
                            audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
                            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,
            status_t    set(audio_stream_type_t streamType,
                            uint32_t sampleRate,
                            uint32_t sampleRate,
                            audio_format_t format,
                            audio_format_t format,
@@ -1349,6 +1381,8 @@ public:
    wp<IAudioTrackCallback> mCallback;                   // callback handler for events, or NULL
    wp<IAudioTrackCallback> mCallback;                   // callback handler for events, or NULL
    sp<IAudioTrackCallback> mLegacyCallbackWrapper;      // wrapper for legacy callback interface
    sp<IAudioTrackCallback> mLegacyCallbackWrapper;      // wrapper for legacy callback interface
    // for notification APIs
    // 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
    bool                    mInitialized = false;   // Set after track is initialized
    // next 2 fields are const after constructor or set()
    // next 2 fields are const after constructor or set()