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

Commit 66206732 authored by Atneya Nair's avatar Atneya Nair Committed by mse1969
Browse files

[RESTRICT AUTOMERGE] Move AudioRecordClient out of AudioPolicyService

Pull out helper classes to assist in further refactoring.

Test: Compiles
Bug: 293603271
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:370bd4b15842f5337f7c55c4cc5ba8028e92839a)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e6b29e7a0480fb4d7e8f0c42d1b5bb440792d08f)
Merged-In: I1881c18b1ef00f3d54006349a6cf3242c747be05
Change-Id: I1881c18b1ef00f3d54006349a6cf3242c747be05
parent d795d3d1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ cc_library_shared {
    name: "libaudiopolicyservice",

    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 −141
Original line number Diff line number Diff line
@@ -35,6 +35,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>
@@ -194,26 +195,6 @@ static void destroyAudioPolicyManager(AudioPolicyInterface *interface)
    delete interface;
}

namespace {
int getTargetSdkForPackageName(std::string_view packageName) {
    const auto binder = defaultServiceManager()->checkService(String16{"package_native"});
    int targetSdk = -1;
    if (binder != nullptr) {
        const auto pm = interface_cast<content::pm::IPackageManagerNative>(binder);
        if (pm != nullptr) {
            const auto status = pm->getTargetSdkVersionForPackage(
                    String16{packageName.data(), packageName.size()}, &targetSdk);
            return status.isOk() ? targetSdk : -1;
        }
    }
    return targetSdk;
}

bool doesPackageTargetAtLeastU(std::string_view packageName) {
    constexpr int ANDROID_API_U = 34;
    return getTargetSdkForPackageName(packageName) >= ANDROID_API_U;
}
} // anonymous
// ----------------------------------------------------------------------------

AudioPolicyService::AudioPolicyService()
@@ -1160,20 +1141,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;
@@ -1859,113 +1826,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());
    int flags = doesPackageTargetAtLeastU(
            mAttributionSource.packageName.value_or("")) ?
            AppOpsManager::WATCH_FOREGROUND_CHANGES : 0;
    // 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(""))),
        flags,
        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>
@@ -63,6 +61,12 @@ using media::audio::common::Int;

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

namespace media::audiopolicy {
    class AudioRecordClient;
}

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

class AudioPolicyService :
    public BinderService<AudioPolicyService>,
    public media::BnAudioPolicyService,
@@ -373,7 +377,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);
@@ -509,6 +512,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:
@@ -699,6 +703,7 @@ private:
        wp<AudioPolicyService> mService;
    };

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

    public:
    class AudioClient : public virtual RefBase {
    public:
                AudioClient(const audio_attributes_t attributes,
@@ -893,82 +899,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 ---
+165 −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 <android/content/pm/IPackageManagerNative.h>

#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;
}

int getTargetSdkForPackageName(std::string_view packageName) {
    const auto binder = defaultServiceManager()->checkService(String16{"package_native"});
    int targetSdk = -1;
    if (binder != nullptr) {
        const auto pm = interface_cast<content::pm::IPackageManagerNative>(binder);
        if (pm != nullptr) {
            const auto status = pm->getTargetSdkVersionForPackage(
                    String16{packageName.data(), packageName.size()}, &targetSdk);
            return status.isOk() ? targetSdk : -1;
        }
    }
    return targetSdk;
}

bool doesPackageTargetAtLeastU(std::string_view packageName) {
    constexpr int ANDROID_API_U = 34;
    return getTargetSdkForPackageName(packageName) >= ANDROID_API_U;
}
}

// 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());

    int flags = doesPackageTargetAtLeastU(
            mAttributionSource.packageName.value_or("")) ?
            AppOpsManager::WATCH_FOREGROUND_CHANGES : 0;
    // 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(""))),
        flags,
        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