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

Commit 7aa76ced authored by Atneya Nair's avatar Atneya Nair
Browse files

[RESTRICT AUTOMERGE] Update uid state based on capability field

Use the passed capability field in the to prevent clients from
recording in the background.

To work around existing issues in the implementation, the approach is
 - if we don't hold the capability, simulate an onUidIdle.
 - if we hold the capability, to simulate an onUidActive and then the
   existing behavior (update the AM state).

Only update behavior for apps targetSdk > 34.

Bug: 268724205
Test: OboeTester recording silenced in background for all paths
Test: OboeTester recording permitted after returning to foreground
Test: AGSA works
Test: atest AudioRecordTest
Change-Id: Ida37fec306417b40006dfac5b5ed04f17418b7c8
parent 9e02a6e3
Loading
Loading
Loading
Loading
+55 −2
Original line number Diff line number Diff line
@@ -21,9 +21,11 @@
#undef __STRICT_ANSI__
#define __STDINT_LIMITS
#define __STDC_LIMIT_MACROS
#include <map>
#include <stdint.h>
#include <sys/time.h>

#include <android/content/pm/IPackageManagerNative.h>
#include <audio_utils/clock.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
@@ -54,6 +56,37 @@ static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds

static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY");

namespace {
int getTargetSdkForPackageName(String16 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(packageName, &targetSdk);
            ALOGI("Capy check package %s, sdk %d", String8(packageName).string(), targetSdk);
            return status.isOk() ? targetSdk : -1;
        }
    }
    return targetSdk;
}

bool doesUidTargetAtLeastU(uid_t uid) {
    Vector<String16> packages;
    PermissionController pc;
    pc.getPackagesForUid(uid, packages);
    constexpr int ANDROID_API_U = 34;
    return packages.empty() || (getTargetSdkForPackageName(packages[0]) >= ANDROID_API_U);
}

bool doesUidTargetAtLeastUCached(uid_t uid) {
    static std::map<uid_t, bool> cache;
    const auto it = cache.find(uid);
    return it == cache.end() ? (cache[uid] = doesUidTargetAtLeastU(uid)) : it->second;
}


} // anonymous
// ----------------------------------------------------------------------------

AudioPolicyService::AudioPolicyService()
@@ -1054,11 +1087,31 @@ void AudioPolicyService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled)
void AudioPolicyService::UidPolicy::onUidStateChanged(uid_t uid,
                                                      int32_t procState,
                                                      int64_t procStateSeq __unused,
                                                      int32_t capability __unused) {
                                                      int32_t capability) {
    if (procState != ActivityManager::PROCESS_STATE_UNKNOWN) {
        if (doesUidTargetAtLeastUCached(uid)) {
            // See ActivityManager.java
            constexpr int32_t PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
            if (capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) {
                // The implementation relies on the assumption that this callback is preceded by
                // onUidActive. This may not be the case if we have lost and then regained the
                // capability, since we simulate onUidIdle below. So, we simulate onUidActive.
                // In the typical case where we  haven't regained capability, this is a no-op, since
                // we should've been preceded by an onUidActive callback anyway.
                updateUid(&mCachedUids, uid, true /* active */,
                        ActivityManager::PROCESS_STATE_UNKNOWN, true /* insert */);
                updateUid(&mCachedUids, uid, true /* active */, procState, true /* insert */);
            } else {
                // If we have lost the capability (e.g. moving to background), treat as-if we have
                // gotten onUidIdle.
                updateUid(&mCachedUids, uid, false /* active */,
                        ActivityManager::PROCESS_STATE_UNKNOWN, true /* insert */);
            }
        } else {
            updateUid(&mCachedUids, uid, true, procState, true);
        }
    }
}

void AudioPolicyService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
    updateUid(&mOverrideUids, uid, active, ActivityManager::PROCESS_STATE_UNKNOWN, insert);