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

Commit 43615ef6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Move AudioRecordClient out of AudioPolicyService"

parents 95916c5b 5b1ed64a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ cc_library {
    ],

    srcs: [
        "AudioRecordClient.cpp",
        "AudioPolicyClientImpl.cpp",
        "AudioPolicyEffects.cpp",
        "AudioPolicyInterfaceImpl.cpp",
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0

#include "AudioPolicyService.h"
#include "AudioRecordClient.h"
#include "TypeConverter.h"
#include <media/AidlConversion.h>
#include <media/AudioPolicy.h>
+1 −117
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <binder/IResultReceiver.h>
#include <utils/String16.h>
#include <utils/threads.h>
#include "AudioRecordClient.h"
#include "AudioPolicyService.h"
#include <hardware_legacy/power.h>
#include <media/AidlConversion.h>
@@ -1164,20 +1165,6 @@ bool AudioPolicyService::isVirtualSource(audio_source_t source)
    return false;
}

/* static */
bool AudioPolicyService::isAppOpSource(audio_source_t source)
{
    switch (source) {
        case AUDIO_SOURCE_FM_TUNER:
        case AUDIO_SOURCE_ECHO_REFERENCE:
        case AUDIO_SOURCE_REMOTE_SUBMIX:
            return false;
        default:
            break;
    }
    return true;
}

void AudioPolicyService::setAppState_l(sp<AudioRecordClient> client, app_state_t state)
{
    AutoCallerClear acc;
@@ -1878,109 +1865,6 @@ binder::Status AudioPolicyService::SensorPrivacyPolicy::onSensorPrivacyChanged(
    return binder::Status::ok();
}

// -----------  AudioPolicyService::OpRecordAudioMonitor implementation ----------

// static
sp<AudioPolicyService::OpRecordAudioMonitor>
AudioPolicyService::OpRecordAudioMonitor::createIfNeeded(
            const AttributionSourceState& attributionSource, const audio_attributes_t& attr,
            wp<AudioCommandThread> commandThread)
{
    if (isAudioServerOrRootUid(attributionSource.uid)) {
        ALOGV("not silencing record for audio or root source %s",
                attributionSource.toString().c_str());
        return nullptr;
    }

    if (!AudioPolicyService::isAppOpSource(attr.source)) {
        ALOGD("not monitoring app op for uid %d and source %d",
                attributionSource.uid, attr.source);
        return nullptr;
    }

    if (!attributionSource.packageName.has_value()
            || attributionSource.packageName.value().size() == 0) {
        return nullptr;
    }
    return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread);
}

AudioPolicyService::OpRecordAudioMonitor::OpRecordAudioMonitor(
        const AttributionSourceState& attributionSource, int32_t appOp,
        wp<AudioCommandThread> commandThread) :
            mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp),
            mCommandThread(commandThread)
{
}

AudioPolicyService::OpRecordAudioMonitor::~OpRecordAudioMonitor()
{
    if (mOpCallback != 0) {
        mAppOpsManager.stopWatchingMode(mOpCallback);
    }
    mOpCallback.clear();
}

void AudioPolicyService::OpRecordAudioMonitor::onFirstRef()
{
    checkOp();
    mOpCallback = new RecordAudioOpCallback(this);
    ALOGV("start watching op %d for %s", mAppOp, mAttributionSource.toString().c_str());
    // TODO: We need to always watch AppOpsManager::OP_RECORD_AUDIO too
    // since it controls the mic permission for legacy apps.
    mAppOpsManager.startWatchingMode(mAppOp, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
        mAttributionSource.packageName.value_or(""))),
        mOpCallback);
}

bool AudioPolicyService::OpRecordAudioMonitor::hasOp() const {
    return mHasOp.load();
}

// Called by RecordAudioOpCallback when the app op corresponding to this OpRecordAudioMonitor
// is updated in AppOp callback and in onFirstRef()
// Note this method is never called (and never to be) for audio server / root track
// due to the UID in createIfNeeded(). As a result for those record track, it's:
// - not called from constructor,
// - not called from RecordAudioOpCallback because the callback is not installed in this case
void AudioPolicyService::OpRecordAudioMonitor::checkOp(bool updateUidStates)
{
    // TODO: We need to always check AppOpsManager::OP_RECORD_AUDIO too
    // since it controls the mic permission for legacy apps.
    const int32_t mode = mAppOpsManager.checkOp(mAppOp,
            mAttributionSource.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
                mAttributionSource.packageName.value_or(""))));
    const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
    // verbose logging only log when appOp changed
    ALOGI_IF(hasIt != mHasOp.load(),
            "App op %d missing, %ssilencing record %s",
            mAppOp, hasIt ? "un" : "", mAttributionSource.toString().c_str());
    mHasOp.store(hasIt);

    if (updateUidStates) {
          sp<AudioCommandThread> commandThread = mCommandThread.promote();
          if (commandThread != nullptr) {
              commandThread->updateUidStatesCommand();
          }
    }
}

AudioPolicyService::OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback(
        const wp<OpRecordAudioMonitor>& monitor) : mMonitor(monitor)
{ }

void AudioPolicyService::OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
            const String16& packageName __unused) {
    sp<OpRecordAudioMonitor> monitor = mMonitor.promote();
    if (monitor != NULL) {
        if (op != monitor->getOp()) {
            return;
        }
        monitor->checkOp(true);
    }
}


// -----------  AudioPolicyService::AudioCommandThread implementation ----------

AudioPolicyService::AudioCommandThread::AudioCommandThread(String8 name,
+9 −77
Original line number Diff line number Diff line

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
@@ -28,7 +27,6 @@
#include <utils/Vector.h>
#include <utils/SortedVector.h>
#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IUidObserver.h>
#include <system/audio.h>
@@ -64,6 +62,12 @@ using media::audio::common::Int;

// ----------------------------------------------------------------------------

namespace media::audiopolicy {
    class AudioRecordClient;
}

using ::android::media::audiopolicy::AudioRecordClient;

class AudioPolicyService :
    public BinderService<AudioPolicyService>,
    public media::BnAudioPolicyService,
@@ -401,7 +405,6 @@ private:
    // Handles binder shell commands
    virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);

    class AudioRecordClient;

    // Sets whether the given UID records only silence
    virtual void setAppState_l(sp<AudioRecordClient> client, app_state_t state) REQUIRES(mLock);
@@ -542,6 +545,7 @@ private:
    // Thread used to send audio config commands to audio flinger
    // For audio config commands, it is necessary because audio flinger requires that the calling
    // process (user) has permission to modify audio settings.
    public:
    class AudioCommandThread : public Thread {
        class AudioCommand;
    public:
@@ -732,6 +736,7 @@ private:
        wp<AudioPolicyService> mService;
    };

    private:
    class AudioPolicyClient : public AudioPolicyClientInterface
    {
     public:
@@ -906,6 +911,7 @@ private:
              bool                                 mAudioVolumeGroupCallbacksEnabled;
    };

    public:
    class AudioClient : public virtual RefBase {
    public:
                AudioClient(const audio_attributes_t attributes,
@@ -927,82 +933,8 @@ private:
        const audio_port_handle_t deviceId;  // selected input device port ID
              bool active;                   // Playback/Capture is active or inactive
    };

    // Checks and monitors app ops for AudioRecordClient
    class OpRecordAudioMonitor : public RefBase {
    public:
        ~OpRecordAudioMonitor() override;
        bool hasOp() const;
        int32_t getOp() const { return mAppOp; }

        static sp<OpRecordAudioMonitor> createIfNeeded(
                const AttributionSourceState& attributionSource,
                const audio_attributes_t& attr, wp<AudioCommandThread> commandThread);

    private:
        OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp,
                wp<AudioCommandThread> commandThread);

        void onFirstRef() override;

        AppOpsManager mAppOpsManager;

        class RecordAudioOpCallback : public BnAppOpsCallback {
        public:
            explicit RecordAudioOpCallback(const wp<OpRecordAudioMonitor>& monitor);
            void opChanged(int32_t op, const String16& packageName) override;

    private:
            const wp<OpRecordAudioMonitor> mMonitor;
        };

        sp<RecordAudioOpCallback> mOpCallback;
        // called by RecordAudioOpCallback when the app op for this OpRecordAudioMonitor is updated
        // in AppOp callback and in onFirstRef()
        // updateUidStates is true when the silenced state of active AudioRecordClients must be
        // re-evaluated
        void checkOp(bool updateUidStates = false);

        std::atomic_bool mHasOp;
        const AttributionSourceState mAttributionSource;
        const int32_t mAppOp;
        wp<AudioCommandThread> mCommandThread;
    };

    // --- AudioRecordClient ---
    // Information about each registered AudioRecord client
    // (between calls to getInputForAttr() and releaseInput())
    class AudioRecordClient : public AudioClient {
    public:
                AudioRecordClient(const audio_attributes_t attributes,
                          const audio_io_handle_t io,
                          const audio_session_t session, audio_port_handle_t portId,
                          const audio_port_handle_t deviceId,
                          const AttributionSourceState& attributionSource,
                          bool canCaptureOutput, bool canCaptureHotword,
                          wp<AudioCommandThread> commandThread) :
                    AudioClient(attributes, io, attributionSource,
                        session, portId, deviceId), attributionSource(attributionSource),
                        startTimeNs(0), canCaptureOutput(canCaptureOutput),
                        canCaptureHotword(canCaptureHotword), silenced(false),
                        mOpRecordAudioMonitor(
                                OpRecordAudioMonitor::createIfNeeded(attributionSource,
                                attributes, commandThread)) {}
                ~AudioRecordClient() override = default;

        bool hasOp() const {
            return mOpRecordAudioMonitor ? mOpRecordAudioMonitor->hasOp() : true;
        }

        const AttributionSourceState attributionSource; // attribution source of client
        nsecs_t startTimeNs;
        const bool canCaptureOutput;
        const bool canCaptureHotword;
        bool silenced;

    private:
        sp<OpRecordAudioMonitor>           mOpRecordAudioMonitor;
    };


    // --- AudioPlaybackClient ---
+140 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AudioRecordClient.h"
#include "AudioPolicyService.h"

namespace android::media::audiopolicy {

using android::AudioPolicyService;

namespace {
bool isAppOpSource(audio_source_t source)
{
    switch (source) {
        case AUDIO_SOURCE_FM_TUNER:
        case AUDIO_SOURCE_ECHO_REFERENCE:
        case AUDIO_SOURCE_REMOTE_SUBMIX:
            return false;
        default:
            break;
    }
    return true;
}
}

// static
sp<OpRecordAudioMonitor>
OpRecordAudioMonitor::createIfNeeded(
            const AttributionSourceState& attributionSource, const audio_attributes_t& attr,
            wp<AudioPolicyService::AudioCommandThread> commandThread)
{
    if (isAudioServerOrRootUid(attributionSource.uid)) {
        ALOGV("not silencing record for audio or root source %s",
                attributionSource.toString().c_str());
        return nullptr;
    }

    if (!isAppOpSource(attr.source)) {
        ALOGD("not monitoring app op for uid %d and source %d",
                attributionSource.uid, attr.source);
        return nullptr;
    }

    if (!attributionSource.packageName.has_value()
            || attributionSource.packageName.value().size() == 0) {
        return nullptr;
    }
    return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread);
}

OpRecordAudioMonitor::OpRecordAudioMonitor(
        const AttributionSourceState& attributionSource, int32_t appOp,
        wp<AudioPolicyService::AudioCommandThread> commandThread) :
            mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp),
            mCommandThread(commandThread)
{
}

OpRecordAudioMonitor::~OpRecordAudioMonitor()
{
    if (mOpCallback != 0) {
        mAppOpsManager.stopWatchingMode(mOpCallback);
    }
    mOpCallback.clear();
}

void OpRecordAudioMonitor::onFirstRef()
{
    checkOp();
    mOpCallback = new RecordAudioOpCallback(this);
    ALOGV("start watching op %d for %s", mAppOp, mAttributionSource.toString().c_str());
    // TODO: We need to always watch AppOpsManager::OP_RECORD_AUDIO too
    // since it controls the mic permission for legacy apps.
    mAppOpsManager.startWatchingMode(mAppOp, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
        mAttributionSource.packageName.value_or(""))),
        AppOpsManager::WATCH_FOREGROUND_CHANGES,
        mOpCallback);
}

bool OpRecordAudioMonitor::hasOp() const {
    return mHasOp.load();
}

// Called by RecordAudioOpCallback when the app op corresponding to this OpRecordAudioMonitor
// is updated in AppOp callback and in onFirstRef()
// Note this method is never called (and never to be) for audio server / root track
// due to the UID in createIfNeeded(). As a result for those record track, it's:
// - not called from constructor,
// - not called from RecordAudioOpCallback because the callback is not installed in this case
void OpRecordAudioMonitor::checkOp(bool updateUidStates)
{
    // TODO: We need to always check AppOpsManager::OP_RECORD_AUDIO too
    // since it controls the mic permission for legacy apps.
    const int32_t mode = mAppOpsManager.checkOp(mAppOp,
            mAttributionSource.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
                mAttributionSource.packageName.value_or(""))));
    const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
    // verbose logging only log when appOp changed
    ALOGI_IF(hasIt != mHasOp.load(),
            "App op %d missing, %ssilencing record %s",
            mAppOp, hasIt ? "un" : "", mAttributionSource.toString().c_str());
    mHasOp.store(hasIt);

    if (updateUidStates) {
          sp<AudioPolicyService::AudioCommandThread> commandThread = mCommandThread.promote();
          if (commandThread != nullptr) {
              commandThread->updateUidStatesCommand();
          }
    }
}

OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback(
        const wp<OpRecordAudioMonitor>& monitor) : mMonitor(monitor)
{ }

void OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
            const String16& packageName __unused) {
    sp<OpRecordAudioMonitor> monitor = mMonitor.promote();
    if (monitor != NULL) {
        if (op != monitor->getOp()) {
            return;
        }
        monitor->checkOp(true);
    }
}

} // android::media::audiopolicy::internal
Loading