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

Commit 4e531c84 authored by Girish's avatar Girish Committed by Girish Shetty
Browse files

implementing concurrent codec metrics

Following changes are made in this CL:
- extend IResourceManagerService interface to allow:
  - notify create/start/stop of codecs
- implement concurrent codec metrics with different
  buckets (such as different resolution, codec type)
  for all the application/process and for the system.
- push the codec concurrency metrics to statsd
- move all metrics to a different class
- update codec reported metrics with codec id

Bug: 265488359
Test: atest cts/tests/media/misc/src/android/media/misc/cts/ResourceManagerTest.java
      /data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
      /data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
      refactoring CL. Existing unit tests still pass.
Change-Id: Ibaa1fb9607e486f2eb79bf02d79c630e09d62b4a
(cherry picked from commit bb36184c)
Merged-In: Ibaa1fb9607e486f2eb79bf02d79c630e09d62b4a
parent c7d3e049
Loading
Loading
Loading
Loading
+80 −9
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <utils/Log.h>

#include <set>
#include <random>
#include <stdlib.h>

#include <inttypes.h>
@@ -99,6 +100,7 @@ static const char *kCodecKeyName = "codec";
// These must be kept synchronized with the constants there.
static const char *kCodecLogSessionId = "android.media.mediacodec.log-session-id";
static const char *kCodecCodec = "android.media.mediacodec.codec";  /* e.g. OMX.google.aac.decoder */
static const char *kCodecId = "android.media.mediacodec.id";
static const char *kCodecMime = "android.media.mediacodec.mime";    /* e.g. audio/mime */
static const char *kCodecMode = "android.media.mediacodec.mode";    /* audio, video */
static const char *kCodecModeVideo = "video";            /* values returned for kCodecMode */
@@ -218,7 +220,7 @@ struct ResourceManagerClient : public BnResourceManagerClient {
        sp<MediaCodec> codec = mMediaCodec.promote();
        if (codec == NULL) {
            // Codec is already gone, so remove the resources as well
            ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
            ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
            std::shared_ptr<IResourceManagerService> service =
                    IResourceManagerService::fromBinder(binder);
            if (service == nullptr) {
@@ -290,6 +292,9 @@ struct MediaCodec::ResourceManagerServiceProxy : public RefBase {
    void removeClient();
    void markClientForPendingRemoval();
    bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
    void notifyClientCreated();
    void notifyClientStarted(ClientConfigParcel& clientConfig);
    void notifyClientStopped(ClientConfigParcel& clientConfig);

    inline void setCodecName(const char* name) {
        mCodecName = name;
@@ -331,7 +336,7 @@ MediaCodec::ResourceManagerServiceProxy::~ResourceManagerServiceProxy() {
}

status_t MediaCodec::ResourceManagerServiceProxy::init() {
    ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
    ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.resource_manager"));
    mService = IResourceManagerService::fromBinder(binder);
    if (mService == nullptr) {
        ALOGE("Failed to get ResourceManagerService");
@@ -468,6 +473,32 @@ bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
    return status.isOk() && success;
}

void MediaCodec::ResourceManagerServiceProxy::notifyClientCreated() {
    ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
                                .uid = static_cast<int32_t>(mUid),
                                .id = getId(mClient),
                                .name = mCodecName};
    mService->notifyClientCreated(clientInfo);
}

void MediaCodec::ResourceManagerServiceProxy::notifyClientStarted(
    ClientConfigParcel& clientConfig) {
    clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
    clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
    clientConfig.clientInfo.id = getId(mClient);
    clientConfig.clientInfo.name = mCodecName;
    mService->notifyClientStarted(clientConfig);
}

void MediaCodec::ResourceManagerServiceProxy::notifyClientStopped(
    ClientConfigParcel& clientConfig) {
    clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
    clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
    clientConfig.clientInfo.id = getId(mClient);
    clientConfig.clientInfo.name = mCodecName;
    mService->notifyClientStopped(clientConfig);
}

////////////////////////////////////////////////////////////////////////////////

MediaCodec::BufferInfo::BufferInfo() : mOwnedByClient(false) {}
@@ -860,6 +891,23 @@ sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() {
    return new PersistentSurface(bufferProducer, bufferSource);
}

// GenerateCodecId generates a 64bit Random ID for each codec that is created.
// The Codec ID is generated as:
//   - A process-unique random high 32bits
//   - An atomic sequence low 32bits
//
static uint64_t GenerateCodecId() {
    static std::atomic_uint64_t sId = [] {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<uint32_t> distrib(0, UINT32_MAX);
        uint32_t randomID = distrib(gen);
        uint64_t id = randomID;
        return id << 32;
    }();
    return sId++;
}

MediaCodec::MediaCodec(
        const sp<ALooper> &looper, pid_t pid, uid_t uid,
        std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
@@ -902,6 +950,7 @@ MediaCodec::MediaCodec(
      mInputBufferCounter(0),
      mGetCodecBase(getCodecBase),
      mGetCodecInfo(getCodecInfo) {
    mCodecId = GenerateCodecId();
    mResourceManagerProxy = new ResourceManagerServiceProxy(pid, uid,
            ::ndk::SharedRefBase::make<ResourceManagerClient>(this, pid, uid));
    if (!mGetCodecBase) {
@@ -1793,6 +1842,12 @@ status_t MediaCodec::init(const AString &name) {
            break;
        }
    }

    if (OK == err) {
        // Notify the ResourceManager that, this codec has been created
        // (initialized) successfully.
        mResourceManagerProxy->notifyClientCreated();
    }
    return err;
}

@@ -1846,6 +1901,7 @@ status_t MediaCodec::configure(
    format->findString("log-session-id", &mLogSessionId);

    if (nextMetricsHandle != 0) {
        mediametrics_setInt64(nextMetricsHandle, kCodecId, mCodecId);
        int32_t profile = 0;
        if (format->findInt32("profile", &profile)) {
            mediametrics_setInt32(nextMetricsHandle, kCodecProfile, profile);
@@ -3340,6 +3396,17 @@ MediaCodec::DequeueOutputResult MediaCodec::handleDequeueOutputBuffer(
    return DequeueOutputResult::kRepliedWithError;
}


inline void MediaCodec::initClientConfigParcel(ClientConfigParcel& clientConfig) {
    clientConfig.codecType = toMediaResourceSubType(mDomain);
    clientConfig.isEncoder = mFlags & kFlagIsEncoder;
    clientConfig.isHardware = !MediaCodecList::isSoftwareCodec(mComponentName);
    clientConfig.width = mWidth;
    clientConfig.height = mHeight;
    clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
    clientConfig.id = mCodecId;
}

void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatCodecNotify:
@@ -3586,14 +3653,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
                    }

                    MediaCodecInfo::Attributes attr = mCodecInfo
                            ? mCodecInfo->getAttributes()
                            : MediaCodecInfo::Attributes(0);
                    if (mDomain == DOMAIN_VIDEO || !(attr & MediaCodecInfo::kFlagIsSoftwareOnly)) {
                        // software audio codecs are currently ignored.
                    mResourceManagerProxy->addResource(MediaResource::CodecResource(
                            mFlags & kFlagIsSecure, toMediaResourceSubType(mDomain)));
                    }

                    postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
                    break;
@@ -3763,6 +3824,11 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        mResourceManagerProxy->addResource(
                                MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
                    }
                    // Notify the RM that the codec is in use (has been started).
                    ClientConfigParcel clientConfig;
                    initClientConfigParcel(clientConfig);
                    mResourceManagerProxy->notifyClientStarted(clientConfig);

                    setState(STARTED);
                    postPendingRepliesAndDeferredMessages("kWhatStartCompleted");

@@ -3993,6 +4059,11 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                              mState, stateString(mState).c_str());
                        break;
                    }
                    // Notify the RM that the codec has been stopped.
                    ClientConfigParcel clientConfig;
                    initClientConfigParcel(clientConfig);
                    mResourceManagerProxy->notifyClientStopped(clientConfig);

                    setState(INITIALIZED);
                    if (mReplyID) {
                        postPendingRepliesAndDeferredMessages("kWhatStopCompleted");
+6 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ namespace aidl {
namespace android {
namespace media {
class MediaResourceParcel;
class ClientConfigParcel;
} // media
} // android
} // aidl
@@ -71,6 +72,7 @@ struct IDescrambler;

using hardware::cas::native::V1_0::IDescrambler;
using aidl::android::media::MediaResourceParcel;
using aidl::android::media::ClientConfigParcel;

struct MediaCodec : public AHandler {
    enum Domain {
@@ -453,6 +455,8 @@ private:
    void updateTunnelPeek(const sp<AMessage> &msg);
    void updatePlaybackDuration(const sp<AMessage> &msg);

    inline void initClientConfigParcel(ClientConfigParcel& clientConfig);

    sp<AMessage> mOutputFormat;
    sp<AMessage> mInputFormat;
    sp<AMessage> mCallback;
@@ -705,6 +709,8 @@ private:
    };

    Histogram mLatencyHist;
    // An unique ID for the codec - Used by the metrics.
    uint64_t mCodecId = 0;

    std::function<sp<CodecBase>(const AString &, const char *)> mGetCodecBase;
    std::function<status_t(const AString &, sp<MediaCodecInfo> *)> mGetCodecInfo;
+55 −1
Original line number Diff line number Diff line
@@ -30,10 +30,64 @@ namespace android {
static constexpr int32_t INVALID_ADJ = -10000;
static constexpr int32_t NATIVE_ADJ = -1000;

/* Make sure this matches with ActivityManager::PROCESS_STATE_NONEXISTENT
 * #include <binder/ActivityManager.h>
 * using ActivityManager::PROCESS_STATE_NONEXISTENT;
 */
static constexpr int32_t PROCESS_STATE_NONEXISTENT = 20;

ProcessInfo::ProcessInfo() {}

/*
 * Checks whether the list of processes with given pids exist or not.
 *
 * Arguments:
 *  - pids (input): List of pids for which to check whether they are Existent or not.
 *  - existent (output): boolean vector corresponds to Existent state of each pids.
 *
 * On successful return:
 *     - existent[i] true corresponds to pids[i] still active and
 *     - existent[i] false corresponds to pids[i] already terminated (Nonexistent)
 * On unsuccessful return, the output argument existent is invalid.
 */
bool ProcessInfo::checkProcessExistent(const std::vector<int32_t>& pids,
                                       std::vector<bool>* existent) {
    sp<IBinder> binder = defaultServiceManager()->waitForService(String16("processinfo"));
    sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);

    // Get the process state of the applications managed/tracked by the ActivityManagerService.
    // Don't have to look into the native processes.
    // If we really need the state of native process, then we can use ==> mOverrideMap
    size_t count = pids.size();
    std::vector<int32_t> states(count, PROCESS_STATE_NONEXISTENT);
    status_t err = service->getProcessStatesFromPids(count,
                                                     const_cast<int32_t*>(pids.data()),
                                                     states.data());
    if (err != OK) {
        ALOGE("%s: IProcessInfoService::getProcessStatesFromPids failed with %d",
              __func__, err);
        return false;
    }

    existent->clear();
    for (size_t index = 0; index < states.size(); index++) {
        // If this process is not tracked by ActivityManagerService, look for overrides.
        if (states[index] == PROCESS_STATE_NONEXISTENT) {
            std::scoped_lock lock{mOverrideLock};
            std::map<int, ProcessInfoOverride>::iterator it =
                mOverrideMap.find(pids[index]);
            if (it != mOverrideMap.end()) {
                states[index] = it->second.procState;
            }
        }
        existent->push_back(states[index] != PROCESS_STATE_NONEXISTENT);
    }

    return true;
}

bool ProcessInfo::getPriority(int pid, int* priority) {
    sp<IBinder> binder = defaultServiceManager()->getService(String16("processinfo"));
    sp<IBinder> binder = defaultServiceManager()->waitForService(String16("processinfo"));
    sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);

    size_t length = 1;
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ struct ProcessInfo : public ProcessInfoInterface {
    virtual bool isPidUidTrusted(int pid, int uid);
    virtual bool overrideProcessInfo(int pid, int procState, int oomScore);
    virtual void removeProcessInfoOverride(int pid);
    bool checkProcessExistent(const std::vector<int32_t>& pids,
                              std::vector<bool>* existent) override;

protected:
    virtual ~ProcessInfo();
+57 −0
Original line number Diff line number Diff line
@@ -17,16 +17,73 @@
#ifndef PROCESS_INFO_INTERFACE_H_
#define PROCESS_INFO_INTERFACE_H_

#include <vector>
#include <utils/RefBase.h>

namespace android {

struct ProcessInfoInterface : public RefBase {
    /*
     * Gets the priority of the process (with given pid) as oom score.
     *
     * @param[in] pid pid of the process.
     * @param[out] priority of the process.
     *
     * @return true for successful return and false otherwise.
     */
    virtual bool getPriority(int pid, int* priority) = 0;
    /*
     * Check whether the given pid is trusted or not.
     *
     * @param[in] pid pid of the process.
     *
     * @return true for trusted process and false otherwise.
     */
    virtual bool isPidTrusted(int pid) = 0;
    /*
     * Check whether the given pid and uid is trusted or not.
     *
     * @param[in] pid pid of the process.
     * @param[in] uid uid of the process.
     *
     * @return true for trusted process and false otherwise.
     */
    virtual bool isPidUidTrusted(int pid, int uid) = 0;
    /*
     * Override process state and oom score of the pid.
     *
     * @param[in] pid pid of the process.
     * @param[in] procState new state of the process to override with.
     * @param[in] oomScore new oom score of the process to override with.
     *
     * @return true upon success and false otherwise.
     */
    virtual bool overrideProcessInfo(int pid, int procState, int oomScore) = 0;
    /*
     * Remove the override info of the given process.
     *
     * @param[in] pid pid of the process.
     */
    virtual void removeProcessInfoOverride(int pid) = 0;
    /*
     * Checks whether the list of processes with given pids exist or not.
     *
     * @param[in] pids List of pids for which to check whether they are Existent or not.
     * @param[out] existent boolean vector corresponds to Existent state of each pids.
     *
     * @return true for successful return and false otherwise.
     * On successful return:
     *     - existent[i] true corresponds to pids[i] still active and
     *     - existent[i] false corresponds to pids[i] already terminated (Nonexistent)
     * On unsuccessful return, the output argument existent is invalid.
     */
    virtual bool checkProcessExistent(const std::vector<int32_t>& pids,
                                      std::vector<bool>* existent) {
        // A default implementation.
        (void)pids;
        (void)existent;
        return false;
    }

protected:
    virtual ~ProcessInfoInterface() {}
Loading