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

Commit e8c8b435 authored by Eric Laurent's avatar Eric Laurent
Browse files

audio policy: implement uid state management for capture

Receive app state updates from ActivityManager and use it to implement
concurrent capture policy.

Bug: 111438757
Test: Manual test with solotester app concurrently with Camera, Duo and
Assistant

Change-Id: I979ad4ecc8b926abb64e1b321b43bd7bd442a8f1
parent 6b6a0f05
Loading
Loading
Loading
Loading
+142 −49
Original line number Diff line number Diff line
@@ -340,15 +340,42 @@ status_t AudioPolicyService::dumpInternals(int fd)
    return NO_ERROR;
}

void AudioPolicyService::setAppState(uid_t uid, app_state_t state)
{
void AudioPolicyService::updateUidStates()
{
    Mutex::Autolock _l(mLock);
        if (mAudioPolicyManager) {
    updateUidStates_l();
}

void AudioPolicyService::updateUidStates_l()
{
    //TODO: implement real concurrent capture policy: for now just apply each app state directly
    for (size_t i =0; i < mAudioRecordClients.size(); i++) {
        sp<AudioRecordClient> current = mAudioRecordClients[i];
        if (!current->active) continue;
        setAppState_l(current->uid, apmStatFromAmState(mUidPolicy->getUidState(current->uid)));
    }
}

/* static */
app_state_t AudioPolicyService::apmStatFromAmState(int amState) {
    switch (amState) {
    case ActivityManager::PROCESS_STATE_UNKNOWN:
        return APP_STATE_IDLE;
    case ActivityManager::PROCESS_STATE_TOP:
        return APP_STATE_TOP;
    default:
        break;
    }
    return APP_STATE_FOREGROUND;
}

void AudioPolicyService::setAppState_l(uid_t uid, app_state_t state)
{
    AutoCallerClear acc;

    if (mAudioPolicyManager) {
        mAudioPolicyManager->setAppState(uid, state);
    }
    }
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    if (af) {
        bool silenced = state == APP_STATE_IDLE;
@@ -511,7 +538,8 @@ void AudioPolicyService::UidPolicy::registerSelf() {
    ActivityManager am;
    am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
            | ActivityManager::UID_OBSERVER_IDLE
            | ActivityManager::UID_OBSERVER_ACTIVE,
            | ActivityManager::UID_OBSERVER_ACTIVE
            | ActivityManager::UID_OBSERVER_PROCSTATE,
            ActivityManager::PROCESS_STATE_UNKNOWN,
            String16("audioserver"));
    status_t res = am.linkToDeath(this);
@@ -538,8 +566,7 @@ void AudioPolicyService::UidPolicy::binderDied(__unused const wp<IBinder> &who)
    mObserverRegistered = false;
}

bool AudioPolicyService::UidPolicy::isUidActive(uid_t uid) {
    if (isServiceUid(uid)) return true;
void AudioPolicyService::UidPolicy::checkRegistered() {
    bool needToReregister = false;
    {
        Mutex::Autolock _l(mLock);
@@ -549,91 +576,157 @@ bool AudioPolicyService::UidPolicy::isUidActive(uid_t uid) {
        // Looks like ActivityManager has died previously, attempt to re-register.
        registerSelf();
    }
}

bool AudioPolicyService::UidPolicy::isUidActive(uid_t uid) {
    if (isServiceUid(uid)) return true;
    checkRegistered();
    {
        Mutex::Autolock _l(mLock);
        auto overrideIter = mOverrideUids.find(uid);
        if (overrideIter != mOverrideUids.end()) {
            return overrideIter->second;
            return overrideIter->second.first;
        }
        // In an absense of the ActivityManager, assume everything to be active.
        if (!mObserverRegistered) return true;
        auto cacheIter = mCachedUids.find(uid);
        if (cacheIter != mCachedUids.end()) {
            return cacheIter->second;
            return cacheIter->second.first;
        }
    }
    ActivityManager am;
    bool active = am.isUidActive(uid, String16("audioserver"));
    {
        Mutex::Autolock _l(mLock);
        mCachedUids.insert(std::pair<uid_t, bool>(uid, active));
        mCachedUids.insert(std::pair<uid_t,
                           std::pair<bool, int>>(uid, std::pair<bool, int>(active,
                                                      ActivityManager::PROCESS_STATE_UNKNOWN)));
    }
    return active;
}

int AudioPolicyService::UidPolicy::getUidState(uid_t uid) {
    if (isServiceUid(uid)) {
        return ActivityManager::PROCESS_STATE_TOP;
    }
    checkRegistered();
    {
        Mutex::Autolock _l(mLock);
        auto overrideIter = mOverrideUids.find(uid);
        if (overrideIter != mOverrideUids.end()) {
            if (overrideIter->second.first) {
                if (overrideIter->second.second != ActivityManager::PROCESS_STATE_UNKNOWN) {
                    return overrideIter->second.second;
                } else {
                    auto cacheIter = mCachedUids.find(uid);
                    if (cacheIter != mCachedUids.end()) {
                        return cacheIter->second.second;
                    }
                }
            }
            return ActivityManager::PROCESS_STATE_UNKNOWN;
        }
        // In an absense of the ActivityManager, assume everything to be active.
        if (!mObserverRegistered) {
            return ActivityManager::PROCESS_STATE_TOP;
        }
        auto cacheIter = mCachedUids.find(uid);
        if (cacheIter != mCachedUids.end()) {
            if (cacheIter->second.first) {
                return cacheIter->second.second;
            } else {
                return ActivityManager::PROCESS_STATE_UNKNOWN;
            }
        }
    }
    ActivityManager am;
    bool active = am.isUidActive(uid, String16("audioserver"));
    int state = ActivityManager::PROCESS_STATE_UNKNOWN;
    if (active) {
        state = am.getUidProcessState(uid, String16("audioserver"));
    }
    {
        Mutex::Autolock _l(mLock);
        mCachedUids.insert(std::pair<uid_t,
                           std::pair<bool, int>>(uid, std::pair<bool, int>(active, state)));
    }
    return state;
}

void AudioPolicyService::UidPolicy::onUidActive(uid_t uid) {
    updateUidCache(uid, true, true);
    updateUid(&mCachedUids, uid, true, ActivityManager::PROCESS_STATE_UNKNOWN, true);
}

void AudioPolicyService::UidPolicy::onUidGone(uid_t uid, __unused bool disabled) {
    updateUidCache(uid, false, false);
    updateUid(&mCachedUids, uid, false, ActivityManager::PROCESS_STATE_UNKNOWN, false);
}

void AudioPolicyService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
    updateUidCache(uid, false, true);
    updateUid(&mCachedUids, uid, false, ActivityManager::PROCESS_STATE_UNKNOWN, true);
}

void AudioPolicyService::UidPolicy::notifyService(uid_t uid, bool active) {
    sp<AudioPolicyService> service = mService.promote();
    if (service != nullptr) {
        service->setAppState(uid, active ?
                              APP_STATE_FOREGROUND :
                              APP_STATE_IDLE);
void AudioPolicyService::UidPolicy::onUidStateChanged(uid_t uid,
                                                      int32_t procState,
                                                      int64_t procStateSeq __unused) {
    if (procState != ActivityManager::PROCESS_STATE_UNKNOWN) {
        updateUid(&mCachedUids, uid, true, procState, true);
    }
}

void AudioPolicyService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
    if (isServiceUid(uid)) return;
    bool wasOverridden = false, wasActive = false;
    {
        Mutex::Autolock _l(mLock);
        updateUidLocked(&mOverrideUids, uid, active, insert, &wasOverridden, &wasActive);
    updateUid(&mOverrideUids, uid, active, ActivityManager::PROCESS_STATE_UNKNOWN, insert);
}
    if (!wasOverridden && insert) {
        notifyService(uid, active);  // Started to override.
    } else if (wasOverridden && !insert) {
        notifyService(uid, isUidActive(uid));  // Override ceased, notify with ground truth.
    } else if (wasActive != active) {
        notifyService(uid, active);  // Override updated.

void AudioPolicyService::UidPolicy::notifyService() {
    sp<AudioPolicyService> service = mService.promote();
    if (service != nullptr) {
        service->updateUidStates();
    }
}

void AudioPolicyService::UidPolicy::updateUidCache(uid_t uid, bool active, bool insert) {
    if (isServiceUid(uid)) return;
    bool wasActive = false;
void AudioPolicyService::UidPolicy::updateUid(std::unordered_map<uid_t,
                                              std::pair<bool, int>> *uids,
                                              uid_t uid,
                                              bool active,
                                              int state,
                                              bool insert) {
    if (isServiceUid(uid)) {
        return;
    }
    bool wasActive = isUidActive(uid);
    int previousState = getUidState(uid);
    {
        Mutex::Autolock _l(mLock);
        updateUidLocked(&mCachedUids, uid, active, insert, nullptr, &wasActive);
        // Do not notify service if currently overridden.
        if (mOverrideUids.find(uid) != mOverrideUids.end()) return;
        updateUidLocked(uids, uid, active, state, insert);
    }
    if (wasActive != isUidActive(uid) || state != previousState) {
        notifyService();
    }
    bool nowActive = active && insert;
    if (wasActive != nowActive) notifyService(uid, nowActive);
}

void AudioPolicyService::UidPolicy::updateUidLocked(std::unordered_map<uid_t, bool> *uids,
        uid_t uid, bool active, bool insert, bool *wasThere, bool *wasActive) {
void AudioPolicyService::UidPolicy::updateUidLocked(std::unordered_map<uid_t,
                                                    std::pair<bool, int>> *uids,
                                                    uid_t uid,
                                                    bool active,
                                                    int state,
                                                    bool insert) {
    auto it = uids->find(uid);
    if (it != uids->end()) {
        if (wasThere != nullptr) *wasThere = true;
        if (wasActive != nullptr) *wasActive = it->second;
        if (insert) {
            it->second = active;
            if (state == ActivityManager::PROCESS_STATE_UNKNOWN) {
                it->second.first = active;
            }
            if (it->second.first) {
                it->second.second = state;
            } else {
                it->second.second = ActivityManager::PROCESS_STATE_UNKNOWN;
            }
        } else {
            uids->erase(it);
        }
    } else if (insert) {
        uids->insert(std::pair<uid_t, bool>(uid, active));
    } else if (insert && (state == ActivityManager::PROCESS_STATE_UNKNOWN)) {
        uids->insert(std::pair<uid_t, std::pair<bool, int>>(uid,
                                      std::pair<bool, int>(active, state)));
    }
}

+18 −8
Original line number Diff line number Diff line
@@ -253,7 +253,7 @@ private:
    virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);

    // Sets whether the given UID records only silence
    virtual void setAppState(uid_t uid, app_state_t state);
    virtual void setAppState_l(uid_t uid, app_state_t state);

    // Overrides the UID state as if it is idle
    status_t handleSetUidState(Vector<String16>& args, int err);
@@ -271,6 +271,11 @@ private:

    status_t getAudioPolicyEffects(sp<AudioPolicyEffects>& audioPolicyEffects);

    app_state_t apmStatFromAmState(int amState);

    void updateUidStates();
    void updateUidStates_l();

    // If recording we need to make sure the UID is allowed to do that. If the UID is idle
    // then it cannot record and gets buffers with zeros - silence. As soon as the UID
    // transitions to an active state we will start reporting buffers with data. This approach
@@ -289,6 +294,7 @@ private:
        void binderDied(const wp<IBinder> &who) override;

        bool isUidActive(uid_t uid);
        int getUidState(uid_t uid);
        void setAssistantUid(uid_t uid) { mAssistantUid = uid; }
        bool isAssistantUid(uid_t uid) { return uid == mAssistantUid; }
        void setA11yUids(const std::vector<uid_t>& uids) { mA11yUids.clear(); mA11yUids = uids; }
@@ -298,22 +304,26 @@ private:
        void onUidActive(uid_t uid) override;
        void onUidGone(uid_t uid, bool disabled) override;
        void onUidIdle(uid_t uid, bool disabled) override;
        void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);

        void addOverrideUid(uid_t uid, bool active) { updateOverrideUid(uid, active, true); }
        void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }

        void updateUid(std::unordered_map<uid_t, std::pair<bool, int>> *uids,
                       uid_t uid, bool active, int state, bool insert);

     private:
        void notifyService(uid_t uid, bool active);
        void notifyService();
        void updateOverrideUid(uid_t uid, bool active, bool insert);
        void updateUidCache(uid_t uid, bool active, bool insert);
        void updateUidLocked(std::unordered_map<uid_t, bool> *uids,
                uid_t uid, bool active, bool insert, bool *wasThere, bool *wasActive);
        void updateUidLocked(std::unordered_map<uid_t, std::pair<bool, int>> *uids,
                             uid_t uid, bool active, int state, bool insert);
        void checkRegistered();

        wp<AudioPolicyService> mService;
        Mutex mLock;
        bool mObserverRegistered;
        std::unordered_map<uid_t, bool> mOverrideUids;
        std::unordered_map<uid_t, bool> mCachedUids;
        std::unordered_map<uid_t, std::pair<bool, int>> mOverrideUids;
        std::unordered_map<uid_t, std::pair<bool, int>> mCachedUids;
        uid_t mAssistantUid;
        std::vector<uid_t> mA11yUids;
    };
+1 −0
Original line number Diff line number Diff line
@@ -536,6 +536,7 @@ private:
        void onUidGone(uid_t uid, bool disabled);
        void onUidActive(uid_t uid);
        void onUidIdle(uid_t uid, bool disabled);
        void onUidStateChanged(uid_t uid __unused, int32_t procState __unused, int64_t procStateSeq __unused) {}

        void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
        void removeOverrideUid(uid_t uid, String16 callingPackage);