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

Commit 0095c258 authored by Atneya Nair's avatar Atneya Nair Committed by Android (Google) Code Review
Browse files

Merge "[audio] Add full hardening metrics" into main

parents 2ea42555 ad19e5b0
Loading
Loading
Loading
Loading
+27 −5
Original line number Diff line number Diff line
@@ -269,6 +269,12 @@ class AfPlaybackCommon : public virtual VolumePortInterface {
    using AppOpsSession = media::permission::AppOpsSession<media::permission::DefaultAppOpsFacade>;

  public:
    enum class EnforcementLevel {
        NONE, // no enforcement
        PARTIAL, // enforcement for CONTROL_PARTIAL
        FULL, // enforcement for CONTROL
    };

    AfPlaybackCommon(IAfTrackBase& self, IAfThreadBase& thread, float volume, bool muted,
                     const audio_attributes_t& attr,
                     const AttributionSourceState& attributionSource,
@@ -284,11 +290,25 @@ class AfPlaybackCommon : public virtual VolumePortInterface {

    // Restricted due to OP_AUDIO_CONTROL_PARTIAL
    bool hasOpControlPartial() const {
        return mOpControlSession ? mHasOpControlPartial.load(std::memory_order_acquire) : true;
        return mOpControlPartialSession ? mHasOpControlPartial.load(std::memory_order_acquire)
                                        : true;
    }

    // Restricted due to OP_AUDIO_CONTROL
    bool hasOpControlFull() const {
        return mOpControlFullSession ? mHasOpControlFull.load(std::memory_order_acquire) : true;
    }

    bool isPlaybackRestrictedControl() const {
        return !(mIsExemptedFromOpControl || hasOpControlPartial());
        using enum EnforcementLevel;
        switch (mEnforcementLevel) {
            case NONE:
                return false;
            case PARTIAL:
                return !hasOpControlPartial();
            case FULL:
                return !hasOpControlFull();
        }
    }

    // VolumePortInterface implementation
@@ -323,13 +343,15 @@ class AfPlaybackCommon : public virtual VolumePortInterface {
    // associated with port
    std::atomic<float> mVolume = 0.0f;

    const bool mIsExemptedFromOpControl;
    const EnforcementLevel mEnforcementLevel;

    std::atomic<bool> mHasOpControlPartial {true};
    std::atomic<bool> mHasOpControlFull {true};
    mutable std::atomic<bool> mPlaybackHardeningLogged {false};
    // the ref behind the optional is const
    // this member is last in decl order to ensure it is destroyed first
    std::optional<AppOpsSession> mOpControlSession;
    // these members are last in decl order to ensure it is destroyed first
    std::optional<AppOpsSession> mOpControlPartialSession;
    std::optional<AppOpsSession> mOpControlFullSession;
};

// Common interface for audioflinger Playback tracks.
+51 −16
Original line number Diff line number Diff line
@@ -3687,19 +3687,21 @@ void PassthruPatchRecord::releaseBuffer(
// ----------------------------------------------------------------------------
// AfPlaybackCommon

static bool shouldExemptFromOpControl(audio_usage_t usage, IAfThreadCallback& cb) {
static AfPlaybackCommon::EnforcementLevel getOpControlEnforcementLevel(audio_usage_t usage,
        IAfThreadCallback& cb) {
    using enum AfPlaybackCommon::EnforcementLevel;
    if (cb.isHardeningOverrideEnabled()) {
        return false;
        return FULL;
    }
    if (hardening_partial()) {
        switch (usage) {
            case AUDIO_USAGE_VIRTUAL_SOURCE:
                return true;
            default:
                return media::permission::isSystemUsage(usage);
    if (usage == AUDIO_USAGE_VIRTUAL_SOURCE || media::permission::isSystemUsage(usage)) {
        return NONE;
    }
    if (hardening_strict()) {
        return FULL;
    } else if (hardening_partial()) {
        return PARTIAL;
    } else {
        return true;
        return NONE;
    }
}

@@ -3711,8 +3713,10 @@ AfPlaybackCommon::AfPlaybackCommon(IAfTrackBase& self, IAfThreadBase& thread, fl
    : mSelf(self),
      mMutedFromPort(muted),
      mVolume(volume),
      mIsExemptedFromOpControl(shouldExemptFromOpControl(attr.usage, *thread.afThreadCallback())) {
      mEnforcementLevel(getOpControlEnforcementLevel(attr.usage, *thread.afThreadCallback())) {
    ALOGI("creating track with enforcement level %d", mEnforcementLevel);
    using AppOpsManager::OP_CONTROL_AUDIO_PARTIAL;
    using AppOpsManager::OP_CONTROL_AUDIO;
    using media::permission::Ops;
    using media::permission::skipOpsForUid;
    using media::permission::ValidatedAttributionSourceState;
@@ -3724,7 +3728,7 @@ AfPlaybackCommon::AfPlaybackCommon(IAfTrackBase& self, IAfThreadBase& thread, fl
                mExecutor.emplace();
            }
            auto thread_wp = wp<IAfThreadBase>::fromExisting(&thread);
            mOpControlSession.emplace(
            mOpControlPartialSession.emplace(
                    ValidatedAttributionSourceState::createFromTrustedSource(attributionSource),
                    Ops{.attributedOp = OP_CONTROL_AUDIO_PARTIAL},
                    [this, isOffloadOrMmap, thread_wp](bool isPermitted) {
@@ -3740,12 +3744,30 @@ AfPlaybackCommon::AfPlaybackCommon(IAfTrackBase& self, IAfThreadBase& thread, fl
                        }
                    }
            );
            // Same as previous but for mHasOpControlFull, OP_CONTROL_AUDIO
            mOpControlFullSession.emplace(
                    ValidatedAttributionSourceState::createFromTrustedSource(attributionSource),
                    Ops{.attributedOp = OP_CONTROL_AUDIO},
                    [this, isOffloadOrMmap, thread_wp](bool isPermitted) {
                        mHasOpControlFull.store(isPermitted, std::memory_order_release);
                        if (isOffloadOrMmap) {
                            mExecutor->enqueue(mediautils::Runnable{[thread_wp]() {
                                auto thread = thread_wp.promote();
                                if (thread != nullptr) {
                                    audio_utils::lock_guard l {thread->mutex()};
                                    thread->broadcast_l();
                                }
                            }});
                        }
                    }
            );
        }
    }
}

void AfPlaybackCommon::maybeLogPlaybackHardening(media::IAudioManagerNative& am) const {
    using media::IAudioManagerNative::HardeningType::PARTIAL;
    using media::IAudioManagerNative::HardeningType::FULL;
    // The op state deviates from if the track is actually muted if the playback was exempted for
    // some compat reason.
    // The state could have technically TOCTOU, but this is for metrics and that is very unlikely
@@ -3755,6 +3777,12 @@ void AfPlaybackCommon::maybeLogPlaybackHardening(media::IAudioManagerNative& am)
                                      /* bypassed= */
                                      !isPlaybackRestrictedControl());
        }
    } else if (!hasOpControlFull()) {
        if (!mPlaybackHardeningLogged.exchange(true, std::memory_order_acq_rel)) {
            am.playbackHardeningEvent(mSelf.uid(), FULL,
                                      /* bypassed= */
                                      !isPlaybackRestrictedControl());
        }
    }
}

@@ -3780,15 +3808,22 @@ void AfPlaybackCommon::processMuteEvent(media::IAudioManagerNative& am, mute_sta
}

void AfPlaybackCommon::startPlaybackDelivery() {
    if (mOpControlSession) {
        mHasOpControlPartial.store(mOpControlSession->beginDeliveryRequest(),
    if (mOpControlPartialSession) {
        mHasOpControlPartial.store(mOpControlPartialSession->beginDeliveryRequest(),
                            std::memory_order_release);
    }
    if (mOpControlFullSession) {
        mHasOpControlFull.store(mOpControlFullSession->beginDeliveryRequest(),
                            std::memory_order_release);
    }
}

void AfPlaybackCommon::endPlaybackDelivery() {
    if (mOpControlSession) {
        mOpControlSession->endDeliveryRequest();
    if (mOpControlPartialSession) {
        mOpControlPartialSession->endDeliveryRequest();
    }
    if (mOpControlFullSession) {
        mOpControlFullSession->endDeliveryRequest();
    }
}