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

Commit b2e5cb5a authored by Francois Gaffie's avatar Francois Gaffie Committed by Eric Laurent
Browse files

[BUG] AudioPolicyManager: prevent patch leak on SwOutput used for bridges



When using either SwBridge or HwBridge, a SwOutput is always involved.
SwBridge: for playback, HwBridge: for volume control (it hosts the
Source Client).

When the bridge ends, the SwOutput shall be rerouted (Sw) or
unrouted (Hw bridge to prevent patch leak).

This CL generalizes the ClientDescriptor usage for all audio patches.
For patches created from APM::createAudioPatch API or call patches witch
are not associated to an active client, it creates an internal client descriptor.
Sink device is expressed as a preferredDevices. Then APM forbids to change
it using UID enforcement in getNewOutputDevices.

It alos allows to track client hence volume sources active on a SwOutput,
even for HwBridge. Waiting for cleaner HwAudioOutputDescriptor, we will use
the mandatory SwOutput declared in configuration file for a given sink device
for HwBridge to attach the Audio Source and control activity, thus volume.
This SwOutput will be routed (aka setOutputDevices to be called) and unrouted
if not needed anymore.

Bug: 187173302

Test: build & audio UC involving bridges
(functional on emulator):
adb shell ./data/AudioPolicyEmulatorTests --gtest_filter=*AudioPatchTest*
adb shell ./data/AudioPolicyEmulatorTests --gtest_filter=*AudioSourceTest*

Signed-off-by: default avatarFrancois Gaffie <francois.gaffie@renault.com>
Change-Id: Ib4dc2ae32a89464bd8ac3b96833f324760012799
parent f68caf6e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ public:
    {
        return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false;
    }
    bool isRouted() const { return mPatchHandle != AUDIO_PATCH_HANDLE_NONE; }

    DeviceVector mDevices; /**< current devices this output is routed to */
    wp<AudioPolicyMix> mPolicyMix;  // non NULL when used by a dynamic policy
+47 −2
Original line number Diff line number Diff line
@@ -56,7 +56,13 @@ public:

    virtual void dump(String8 *dst, int spaces) const;
    virtual std::string toShortString() const;

    /**
     * @brief isInternal
     * @return true if the client corresponds to an audio patch created from createAudioPatch API or
     * for call audio routing, or false if the client corresponds to an AudioTrack, AudioRecord or
     * HW Audio Source.
     */
    virtual bool isInternal() const { return false; }
    audio_port_handle_t portId() const { return mPortId; }
    uid_t uid() const { return mUid; }
    audio_session_t session() const { return mSessionId; };
@@ -69,8 +75,16 @@ public:
    bool isPreferredDeviceForExclusiveUse() const { return mPreferredDeviceForExclusiveUse; }
    virtual void setActive(bool active) { mActive = active; }
    bool active() const { return mActive; }
    /**
     * @brief hasPreferredDevice Note that as internal clients use preferred device for convenience,
     * we do hide this internal behavior to prevent from regression (like invalidating track for
     * clients following same strategies...)
     * @param activeOnly
     * @return
     */
    bool hasPreferredDevice(bool activeOnly = false) const {
        return mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
        return !isInternal() &&
                mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
    }

private:
@@ -211,6 +225,8 @@ public:
        mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
        mSinkDevice = nullptr;
    }
    void setUseSwBridge() { mUseSwBridge = true; }
    bool useSwBridge() const { return mUseSwBridge; }
    bool isConnected() const { return mPatchHandle != AUDIO_PATCH_HANDLE_NONE; }
    audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
    sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
@@ -229,6 +245,35 @@ public:
    sp<DeviceDescriptor> mSinkDevice;
    wp<SwAudioOutputDescriptor> mSwOutput;
    wp<HwAudioOutputDescriptor> mHwOutput;
    bool mUseSwBridge = false;
};

/**
 * @brief The InternalSourceClientDescriptor class
 * Specialized Client Descriptor for either a raw patch created from @see createAudioPatch API
 * or for internal audio patches managed by APM (e.g. phone call patches).
 * Whatever the bridge created (software or hardware), we need a client to track the activity
 * and manage volumes.
 * The Audio Patch requested sink is expressed as a preferred device which allows to route
 * the SwOutput. Then APM will performs checks on the UID (against UID of Audioserver) of the
 * requester to prevent rerouting SwOutput involved in raw patches.
 */
class InternalSourceClientDescriptor: public SourceClientDescriptor
{
public:
    InternalSourceClientDescriptor(
            audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
            const struct audio_port_config &config, const sp<DeviceDescriptor>& srcDevice,
             const sp<DeviceDescriptor>& sinkDevice,
            product_strategy_t strategy, VolumeSource volumeSource) :
        SourceClientDescriptor(
            portId, uid, attributes, config, srcDevice, AUDIO_STREAM_PATCH, strategy,
            volumeSource)
    {
        setPreferredDeviceId(sinkDevice->getId());
    }
    bool isInternal() const override { return true; }
    ~InternalSourceClientDescriptor() override = default;
};

class SourceClientCollection :
+2 −1
Original line number Diff line number Diff line
@@ -100,7 +100,8 @@ SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t
    TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
        {config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
        stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
        {} /* Sources do not support secondary outputs*/, nullptr), mSrcDevice(srcDevice)
        {} /* Sources do not support secondary outputs*/, nullptr),
    mSrcDevice(srcDevice)
{
}

+214 −148

File changed.

Preview size limit exceeded, changes collapsed.

+25 −12
Original line number Diff line number Diff line
@@ -266,10 +266,7 @@ public:
        virtual status_t getAudioPort(struct audio_port_v7 *port);
        virtual status_t createAudioPatch(const struct audio_patch *patch,
                                           audio_patch_handle_t *handle,
                                           uid_t uid) {
            return createAudioPatchInternal(patch, handle, uid);
        }

                                           uid_t uid);
        virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
                                              uid_t uid);
        virtual status_t listAudioPatches(unsigned int *num_patches,
@@ -647,7 +644,12 @@ protected:

        void connectTelephonyRxAudioSource();

        void disconnectTelephonyRxAudioSource();
        void disconnectTelephonyAudioSource(audio_port_handle_t &portHandle);

        void connectTelephonyTxAudioSource(const sp<DeviceDescriptor> &srcdevice,
                                           const sp<DeviceDescriptor> &sinkDevice,
                                           uint32_t delayMs);


        /**
         * @brief updates routing for all inputs.
@@ -854,6 +856,12 @@ protected:
        status_t connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
        status_t disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);

        status_t connectAudioSourceToSink(const sp<SourceClientDescriptor>& sourceDesc,
                                          const sp<DeviceDescriptor> &sinkDevice,
                                          const struct audio_patch *patch,
                                          audio_patch_handle_t &handle,
                                          uid_t uid, uint32_t delayMs);

        sp<SourceClientDescriptor> getSourceForAttributesOnOutput(audio_io_handle_t output,
                                                                  const audio_attributes_t &attr);
        void clearAudioSourcesForOutput(audio_io_handle_t output);
@@ -904,8 +912,6 @@ protected:

        SoundTriggerSessionCollection mSoundTriggerSessions;

        sp<AudioPatch> mCallTxPatch;

        HwAudioOutputCollection mHwOutputs;
        SourceClientCollection mAudioSources;

@@ -947,6 +953,7 @@ protected:
        // The port handle of the hardware audio source created internally for the Call RX audio
        // end point.
        audio_port_handle_t mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE;
        audio_port_handle_t mCallTxSourceClientPort = AUDIO_PORT_HANDLE_NONE;

        // Support for Multi-Stream Decoder (MSD) module
        sp<DeviceDescriptor> getMsdAudioInDevice() const;
@@ -978,6 +985,8 @@ protected:
        // Called by setDeviceConnectionState()
        status_t deviceToAudioPort(audio_devices_t deviceType, const char* device_address,
                                   const char* device_name, media::AudioPort* aidPort);
        bool isMsdPatch(const audio_patch_handle_t &handle) const;

private:
        void onNewAudioModulesAvailableInt(DeviceVector *newDevices);

@@ -1123,21 +1132,25 @@ private:
         * @param[out] handle patch handle to be provided if patch installed correctly
         * @param[in] uid of the client
         * @param[in] delayMs if required
         * @param[in] sourceDesc [optional] in case of external source, source client to be
         * configured by the patch, i.e. assigning an Output (HW or SW)
         * @param[in] sourceDesc source client to be configured when creating the patch, i.e.
         *            assigning an Output (HW or SW) used for volume control.
         * @return NO_ERROR if patch installed correctly, error code otherwise.
         */
        status_t createAudioPatchInternal(const struct audio_patch *patch,
                                          audio_patch_handle_t *handle,
                                          uid_t uid, uint32_t delayMs = 0,
                                          const sp<SourceClientDescriptor>& sourceDesc = nullptr);
                                          uid_t uid, uint32_t delayMs,
                                          const sp<SourceClientDescriptor>& sourceDesc);
        /**
         * @brief releaseAudioPatchInternal internal function to remove an audio patch
         * @param[in] handle of the patch to be removed
         * @param[in] delayMs if required
         * @param[in] sourceDesc [optional] in case of external source, source client to be
         * unrouted from the patch, i.e. assigning an Output (HW or SW)
         * @return NO_ERROR if patch removed correctly, error code otherwise.
         */
        status_t releaseAudioPatchInternal(audio_patch_handle_t handle, uint32_t delayMs = 0);
        status_t releaseAudioPatchInternal(audio_patch_handle_t handle,
                                           uint32_t delayMs = 0,
                                           const sp<SourceClientDescriptor>& sourceDesc = nullptr);

        status_t installPatch(const char *caller,
                audio_patch_handle_t *patchHandle,