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

Commit 0ac5c21d authored by Girish's avatar Girish
Browse files

resourcemanager: define resource model

This change:
- defines a resource model interface
- defines a base resource model that implements the current (default) resource model
- integrates the resource model with the resource manager service
This change allows extending or replacing the resource models in the future.

Bug: 294886363
Test: atest android.media.misc.cts.ResourceManagerTest
      atest android.media.misc.cts.ResourceManagerMultiTest
      /data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
      /data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
Change-Id: Ifbdd3de90bf9fc5e21f2e1eaa9993dcc0983810a
parent 6a6044d8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ cc_library {
    name: "libresourcemanagerservice",

    srcs: [
        "DefaultResourceModel.cpp",
        "ResourceManagerMetrics.cpp",
        "ResourceManagerService.cpp",
        "ResourceManagerServiceNew.cpp",
+145 −0
Original line number Diff line number Diff line
/*
**
** Copyright 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.
*/

//#define LOG_NDEBUG 0
#define LOG_TAG "DefaultResourceModel"
#include <utils/Log.h>

#include "ResourceManagerServiceUtils.h"
#include "DefaultResourceModel.h"
#include "ResourceTracker.h"

namespace android {

DefaultResourceModel::DefaultResourceModel(
        const std::shared_ptr<ResourceTracker>& resourceTracker,
        bool supportsMultipleSecureCodecs,
        bool supportsSecureWithNonSecureCodec)
    : mSupportsMultipleSecureCodecs(supportsMultipleSecureCodecs),
      mSupportsSecureWithNonSecureCodec(supportsSecureWithNonSecureCodec),
      mResourceTracker(resourceTracker) {
}

DefaultResourceModel::~DefaultResourceModel() {
}

bool DefaultResourceModel::getAllClients(
        const ReclaimRequestInfo& reclimRequestInfo,
        std::vector<ClientInfo>& clients) {

    clients.clear();
    MediaResourceParcel mediaResource{.type = reclimRequestInfo.mResources[0].type,
                                      .subType = reclimRequestInfo.mResources[0].subType};
    ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};

    // Resolve the secure-unsecure codec conflicts if there is any.
    switch (reclimRequestInfo.mResources[0].type) {
    case MediaResource::Type::kSecureCodec:
        // Looking to start a secure codec.
        // #1. Make sure if multiple secure codecs can coexist
        if (!mSupportsMultipleSecureCodecs) {
            if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
                // A higher priority process owns an instance of a secure codec.
                // So this request can't be fulfilled.
                return false;
            }
        }
        // #2. Make sure a secure codec can coexist if there is an instance
        // of non-secure codec running already.
        if (!mSupportsSecureWithNonSecureCodec) {
            mediaResource.type = MediaResource::Type::kNonSecureCodec;
            if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
                // A higher priority process owns an instance of a non-secure codec.
                // So this request can't be fulfilled.
                return false;
            }
        }
        break;
    case MediaResource::Type::kNonSecureCodec:
        // Looking to start a non-secure codec.
        // Make sure a non-secure codec can coexist if there is an instance
        // of secure codec running already.
        if (!mSupportsSecureWithNonSecureCodec) {
            mediaResource.type = MediaResource::Type::kSecureCodec;
            if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
                // A higher priority process owns an instance of a secure codec.
                // So this request can't be fulfilled.
                return false;
            }
        }
        break;
    default:
        break;
    }

    if (!clients.empty()) {
        // There is secure/unsecure codec co-existence conflict
        // and we have only found processes with lower priority holding the
        // resources. So, all of these need to be reclaimed.
        return false;
    }

    // No more resource conflicts.
    switch (reclimRequestInfo.mResources[0].type) {
    case MediaResource::Type::kSecureCodec:
    case MediaResource::Type::kNonSecureCodec:
        // Handling Codec resource reclaim
        return getCodecClients(reclimRequestInfo, clients);
    case MediaResource::Type::kGraphicMemory:
    case MediaResource::Type::kDrmSession:
        // Handling DRM and GraphicMemory resource reclaim
        mediaResource.id = reclimRequestInfo.mResources[0].id;
        mediaResource.value = reclimRequestInfo.mResources[0].value;
        return mResourceTracker->getAllClients(resourceRequestInfo, clients);
    default:
        break;
    }

    return !clients.empty();
}

bool DefaultResourceModel::getCodecClients(
        const ReclaimRequestInfo& reclimRequestInfo,
        std::vector<ClientInfo>& clients) {
    MediaResourceParcel mediaResource;
    ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};

    // 1. Look to find the client(s) with the other resources, for the given
    // primary type.
    MediaResource::SubType primarySubType = reclimRequestInfo.mResources[0].subType;
    for (size_t index = 1; index < reclimRequestInfo.mResources.size(); index++) {
        mediaResource.type = reclimRequestInfo.mResources[index].type;
        mediaResource.subType = reclimRequestInfo.mResources[index].subType;
        mResourceTracker->getAllClients(resourceRequestInfo, clients, primarySubType);
    }

    // 2. Get all clients of the same type.
    mediaResource.type = reclimRequestInfo.mResources[0].type;
    mediaResource.subType = reclimRequestInfo.mResources[0].subType;
    mResourceTracker->getAllClients(resourceRequestInfo, clients);

    // 3. Get all cliends of the different type.
    MediaResourceType otherType =
        (reclimRequestInfo.mResources[0].type == MediaResource::Type::kSecureCodec) ?
        MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
    mediaResource.type = otherType;
    mResourceTracker->getAllClients(resourceRequestInfo, clients);

    return !clients.empty();
}

} // namespace android
+73 −0
Original line number Diff line number Diff line
/*
**
** Copyright 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.
*/

#ifndef ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_
#define ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_

#include "IResourceModel.h"

namespace android {

class ResourceTracker;

/*
 * Implements the Default Resource Model that handles:
 *   - coexistence of secure codec with another secure/non-secure codecs
 *   - sharing resources among other codecs
 */
class DefaultResourceModel : public IResourceModel {
public:
    DefaultResourceModel(const std::shared_ptr<ResourceTracker>& resourceTracker,
                         bool supportsMultipleSecureCodecs = true,
                         bool supportsSecureWithNonSecureCodec = true);
    virtual ~DefaultResourceModel();

    /*
     * Set the codec co-existence properties
     */
    void config(bool supportsMultipleSecureCodecs, bool supportsSecureWithNonSecureCodec) {
        mSupportsMultipleSecureCodecs = supportsMultipleSecureCodecs;
        mSupportsSecureWithNonSecureCodec = supportsSecureWithNonSecureCodec;
    }

    /*
     * Get a list of all clients that holds the resources requested.
     * This implementation uses the ResourceModel to select the clients.
     *
     * @param[in]  reclaimRequestInfo Information about the Reclaim request
     * @param[out] cliens The list of clients that hold the resources in question.
     *
     * @return true if there aren't any resource conflicts and false otherwise.
     */
    bool getAllClients(const ReclaimRequestInfo& reclaimRequestInfo,
                       std::vector<ClientInfo>& clients) override;

protected:
    bool getCodecClients(const ReclaimRequestInfo& reclaimRequestInfo,
                         std::vector<ClientInfo>& clients);

protected:
    // Keeping these protected to allow extending this implementation
    // by other resource models.
    bool mSupportsMultipleSecureCodecs;
    bool mSupportsSecureWithNonSecureCodec;
    std::shared_ptr<ResourceTracker> mResourceTracker;
};

} // namespace android

#endif  // ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_
+67 −0
Original line number Diff line number Diff line
/*
**
** Copyright 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.
*/

#ifndef ANDROID_MEDIA_IRESOURCEMODEL_H_
#define ANDROID_MEDIA_IRESOURCEMODEL_H_

#include <memory>
#include <vector>

#include <aidl/android/media/IResourceManagerClient.h>
#include <aidl/android/media/MediaResourceParcel.h>

namespace android {

struct ClientInfo;
struct ReclaimRequestInfo;

/*
 * Interface that defines Resource Model.
 *
 * This provides an interface that manages the resource model.
 * The primary functionality of the implementation of this resource model is to:
 *  1. Define a resource model for a device (or family of devices)
 *    For example (and not limited to):
 *      - Can a secure codec coexist with another secure or unsecured codec?
 *      - How many codecs can coexist?
 *      - Can one type of codecs (for example avc) coexist with another type of codec
 *        (for example hevc) independently? OR are they sharing the common
 *        resource pool?
 *  2. Provide a list of clients that hold requesting resources.
 */
class IResourceModel {
public:
    IResourceModel() {}

    virtual ~IResourceModel() {}

    /*
     * Get a list of all clients that holds the resources requested.
     * This implementation uses the ResourceModel to select the clients.
     *
     * @param[in]  reclaimRequestInfo Information about the Reclaim request
     * @param[out] clients The list of clients that hold the resources in question.
     *
     * @return true if there aren't any resource conflicts and false otherwise.
     */
    virtual bool getAllClients(const ReclaimRequestInfo& reclaimRequestInfo,
                               std::vector<ClientInfo>& clients) = 0;
};

} // namespace android

#endif  // ANDROID_MEDIA_IRESOURCEMODEL_H_
+107 −91
Original line number Diff line number Diff line
@@ -491,17 +491,10 @@ void ResourceManagerService::getClientForResource_l(
    }
}

Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInfo,
        const std::vector<MediaResourceParcel>& resources, bool* _aidl_return) {
    int32_t callingPid = clientInfo.pid;
    std::string clientName = clientInfo.name;
    String8 log = String8::format("reclaimResource(callingPid %d, uid %d resources %s)",
            callingPid, clientInfo.uid, getString(resources).c_str());
    mServiceLog->add(log);
    *_aidl_return = false;

    std::vector<ClientInfo> targetClients;
    {
bool ResourceManagerService::getTargetClients(
        int32_t callingPid,
        const std::vector<MediaResourceParcel>& resources,
        std::vector<ClientInfo>& targetClients) {
    std::scoped_lock lock{mLock};
    if (!mProcessInfo->isPidTrusted(callingPid)) {
        pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
@@ -539,13 +532,13 @@ Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInf
        ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
        if (!mSupportsMultipleSecureCodecs) {
            if (!getAllClients_l(resourceRequestInfo, targetClients)) {
                    return Status::ok();
                return false;
            }
        }
        if (!mSupportsSecureWithNonSecureCodec) {
            mediaResource.type = MediaResource::Type::kNonSecureCodec;
            if (!getAllClients_l(resourceRequestInfo, targetClients)) {
                    return Status::ok();
                return false;
            }
        }
    }
@@ -555,7 +548,7 @@ Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInf
                                              .subType = nonSecureCodec->subType};
            ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
            if (!getAllClients_l(resourceRequestInfo, targetClients)) {
                    return Status::ok();
                return false;
            }
        }
    }
@@ -564,7 +557,7 @@ Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInf
        ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
        getClientForResource_l(resourceRequestInfo, targetClients);
        if (targetClients.size() == 0) {
                return Status::ok();
            return false;
        }
    }

@@ -599,6 +592,29 @@ Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInf
            getClientForResource_l(resourceRequestInfo, targetClients);
        }
    }

    return !targetClients.empty();
}

Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInfo,
        const std::vector<MediaResourceParcel>& resources, bool* _aidl_return) {
    int32_t callingPid = clientInfo.pid;
    std::string clientName = clientInfo.name;
    String8 log = String8::format("reclaimResource(callingPid %d, uid %d resources %s)",
            callingPid, clientInfo.uid, getString(resources).c_str());
    mServiceLog->add(log);
    *_aidl_return = false;

    // Check if there are any resources to be reclaimed before processing.
    if (resources.empty()) {
        return Status::ok();
    }

    std::vector<ClientInfo> targetClients;
    if (!getTargetClients(callingPid, resources, targetClients)) {
        // Nothing to reclaim from.
        ALOGI("%s: There aren't any clients to reclaim from", __func__);
        return Status::ok();
    }

    *_aidl_return = reclaimUnconditionallyFrom(targetClients);
Loading