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

Commit 6c16adb3 authored by Girish's avatar Girish
Browse files

resourcemanager: define reclaim policy

Refactor the current design of the ResourceManagerService to
introduce Reclaim Policies.
This defines and implements the priority (oom score) of the process
as the default reclaim policy.
This change allows extending reclaim policies.

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: I0de0d86c08b1b148e2f813b884aa693b1643900c
parent 0ac5c21d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ cc_library {

    srcs: [
        "DefaultResourceModel.cpp",
        "ProcessPriorityReclaimPolicy.cpp",
        "ResourceManagerMetrics.cpp",
        "ResourceManagerService.cpp",
        "ResourceManagerServiceNew.cpp",
+58 −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_IRECLAIMPOLICY_H_
#define ANDROID_MEDIA_IRECLAIMPOLICY_H_

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

namespace android {

struct ClientInfo;
struct ReclaimRequestInfo;

/*
 * Interface that defines Reclaim Policy.
 *
 * This provides an interface to select/identify a client based on a specific
 * Reclaim policy.
 */
class IReclaimPolicy {
public:
    IReclaimPolicy() {}

    virtual ~IReclaimPolicy() {}

    /*
     * Based on the Reclaim policy, identify and return a client from the list
     * of given clients that satisfy the resource requested.
     *
     * @param[in]  reclaimRequestInfo Information about the resource request
     * @param[in]  client List of clients to select from.
     * @param[out] targetClients Upon success, this will have the list of identified client(s).
     *
     * @return true on success, false otherwise
     */
    virtual bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
                            const std::vector<ClientInfo>& clients,
                            std::vector<ClientInfo>& targetClients) = 0;
};

} // namespace android

#endif  // ANDROID_MEDIA_IRECLAIMPOLICY_H_
+135 −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 "ProcessPriorityReclaimPolicy"
#include <utils/Log.h>

#include "ResourceTracker.h"
#include "ResourceManagerService.h"
#include "ProcessPriorityReclaimPolicy.h"

namespace android {

using aidl::android::media::IResourceManagerClient;

ProcessPriorityReclaimPolicy::ProcessPriorityReclaimPolicy(
        const std::shared_ptr<ResourceTracker>& resourceTracker)
    : mResourceTracker(resourceTracker) {
}

ProcessPriorityReclaimPolicy::~ProcessPriorityReclaimPolicy() {
}

// Process priority (oom score) based reclaim:
//   - Find a process with lowest priority (than that of calling process).
//   - Find the bigegst client (with required resources) from that process.
bool ProcessPriorityReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
                                              const std::vector<ClientInfo>& clients,
                                              std::vector<ClientInfo>& targetClients) {
    // NOTE: This is the behavior of the existing reclaim policy.
    // We can alter it to select more than one client to reclaim from, depending
    // on the reclaim polocy.

    MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
    MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
    // Find one client to reclaim the needed resources from.
    // 1. Get the priority of the (reclaim) requesting process.
    int callingPid = reclaimRequestInfo.mCallingPid;
    int callingPriority = -1;
    if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
        ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
        return false;
    }

    ClientInfo clientInfo;
    // 2 Look to find the biggest client from the lowest priority process that
    // has the other resources and with the given primary type.
    bool found = false;
    int lowestPriority = -1;
    MediaResource::SubType primarySubType = subType;
    for (size_t index = 1; !found && (index < reclaimRequestInfo.mResources.size()); index++) {
        MediaResource::Type type = reclaimRequestInfo.mResources[index].type;
        MediaResource::SubType subType = reclaimRequestInfo.mResources[index].subType;
        found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
                                                   type, subType, primarySubType,
                                                   clients, clientInfo, lowestPriority);
    }
    // 3 If we haven't found a client yet, then select the biggest client of primary type.
    if (!found) {
        found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
                                                   type, subType,
                                                   MediaResource::SubType::kUnspecifiedSubType,
                                                   clients, clientInfo, lowestPriority);
    }
    // 4 If we haven't found a client yet, then select the biggest client of different type.
    // This is applicable for code type only.
    if (!found) {
        if (type != MediaResource::Type::kSecureCodec &&
            type != MediaResource::Type::kNonSecureCodec) {
            return false;
        }
        MediaResourceType otherType = (type == MediaResource::Type::kSecureCodec) ?
            MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
        if (!getBiggestClientFromLowestPriority(callingPid, callingPriority,
                                                otherType, subType,
                                                MediaResource::SubType::kUnspecifiedSubType,
                                                clients, clientInfo, lowestPriority)) {
            return false;
        }
    }

    targetClients.emplace_back(clientInfo);
    ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
          __func__, callingPid, callingPriority, clientInfo.mPid, lowestPriority);

    return true;
}

bool ProcessPriorityReclaimPolicy::getBiggestClientFromLowestPriority(
        pid_t callingPid,
        int callingPriority,
        MediaResource::Type type, MediaResource::SubType subType,
        MediaResource::SubType primarySubType,
        const std::vector<ClientInfo>& clients,
        ClientInfo& targetClient,
        int& lowestPriority) {
    // 1. Find the lowest priority process among all the clients with the
    // requested resource type.
    int lowestPriorityPid = -1;
    lowestPriority = -1;
    if (!mResourceTracker->getLowestPriorityPid(type, subType, primarySubType, clients,
                                                lowestPriorityPid, lowestPriority)) {
        ALOGD("%s: can't find a process with lower priority than that of the process[%d:%d]",
              __func__, callingPid, callingPriority);
        return false;
    }

    // 2. Make sure that the priority of the target process is less than
    // requesting process.
    if (lowestPriority <= callingPriority) {
        ALOGD("%s: lowest priority %d vs caller priority %d",
              __func__, lowestPriority, callingPriority);
        return false;
    }

    // 3. Look to find the biggest client from that process for the given resources
    return mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType,
                                              clients, targetClient, primarySubType);
}

} // namespace android
+89 −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_PROCESSPRIORITYRECLAIMPOLICY_H_
#define ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_

#include <media/MediaResource.h>
#include "IReclaimPolicy.h"

namespace android {

class ResourceTracker;
struct ClientInfo;

/*
 * Implementation of the Reclaim Policy based on the process priority.
 *
 * Find the lowest priority process (lower than the calling/requesting process’s priority)
 * that has the required resources.
 * From that process, find the biggest client and return the same for reclaiming.
 * If there is a codec co-existence policy, that is addressed as below:
 *   - if these are any conflicting codecs, reclaim all those conflicting clients.
 * If no conflicting codecs, the reclaim policy will select a client in the order of:
 *   - Find the biggest client from the lowest priority process that
 *     has the other resources and with the given primary type.
 *   - select the biggest client from the lower priority process that
 *     has the primary type.
 *   - If it's a codec reclaim request, then:
 *      - select the biggest client from the lower priority process that
 *        has the othe type (for example secure for a non-secure and vice versa).
 */
class ProcessPriorityReclaimPolicy : public IReclaimPolicy {
public:
    ProcessPriorityReclaimPolicy(const std::shared_ptr<ResourceTracker>& resourceTracker);

    virtual ~ProcessPriorityReclaimPolicy();

    /*
     * Based on the process priority, identify and return a client from the list
     * of given clients that satisfy the resource requested.
     *
     * @param[in]  reclaimRequestInfo Information about the resource request
     * @param[in]  client List of clients to select from.
     * @param[out] targetClients Upon success, this will have the list of identified client(s).
     *
     * @return true on success, false otherwise
     */
    bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
                    const std::vector<ClientInfo>& clients,
                    std::vector<ClientInfo>& targetClients) override;

private:

    // Get the biggest client with the given resources from the given list of clients.
    // The client should belong to lowest possible priority than that of the
    // calling/requesting process.
    // returns true on success, false otherwise
    //
    bool getBiggestClientFromLowestPriority(
        pid_t callingPid,
        int callingPriority,
        MediaResource::Type type,
        MediaResource::SubType subType,
        MediaResource::SubType primarySubType,
        const std::vector<ClientInfo>& clients,
        ClientInfo& targetClient,
        int& lowestPriority);

private:
    std::shared_ptr<ResourceTracker> mResourceTracker;
};

} // namespace android

#endif  // ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
+27 −49
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <mediautils/ProcessInfo.h>

#include "DefaultResourceModel.h"
#include "ProcessPriorityReclaimPolicy.h"
#include "ResourceManagerServiceNew.h"
#include "ResourceTracker.h"
#include "ServiceLog.h"
@@ -40,6 +41,7 @@ void ResourceManagerServiceNew::init() {
    mResourceTracker = std::make_shared<ResourceTracker>(ref<ResourceManagerServiceNew>(),
                                                         mProcessInfo);
    setUpResourceModels();
    setUpReclaimPolicies();
}

void ResourceManagerServiceNew::setUpResourceModels() {
@@ -57,6 +59,12 @@ void ResourceManagerServiceNew::setUpResourceModels() {
    }
}

void ResourceManagerServiceNew::setUpReclaimPolicies() {
    mReclaimPolicies.clear();
    // Process priority (oom score) as the Default reclaim policy.
    mReclaimPolicies.push_back(std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker));
}

Status ResourceManagerServiceNew::config(const std::vector<MediaResourcePolicyParcel>& policies) {
    Status status = ResourceManagerService::config(policies);
    // Change in the config dictates update to the resource model.
@@ -241,6 +249,7 @@ bool ResourceManagerServiceNew::getTargetClients(
        // Since there was a conflict, we need to reclaim all elements.
        targetClients = std::move(clients);
    } else {
        // Select a client among those have the needed resources.
        getClientForResource_l(reclaimRequestInfo, clients, targetClients);
    }
    return !targetClients.empty();
@@ -263,59 +272,14 @@ void ResourceManagerServiceNew::getClientForResource_l(
        }
    }

    // Now find client(s) from a lowest priority process that has needed resources.
    ResourceRequestInfo resourceRequestInfo {callingPid, nullptr};
    for (const MediaResourceParcel& resource : reclaimRequestInfo.mResources) {
        resourceRequestInfo.mResource = &resource;
        if (getLowestPriorityProcessBiggestClient_l(resourceRequestInfo, clients, targetClient)) {
            targetClients.emplace_back(targetClient);
    // Run through all the reclaim policies until a client to reclaim from is identified.
    for (std::unique_ptr<IReclaimPolicy>& reclaimPolicy : mReclaimPolicies) {
        if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
            return;
        }
    }
}

// Process priority (oom score) based reclaim:
//   - Find a process with lowest priority (than that of calling process).
//   - Find the bigegst client (with required resources) from that process.
bool ResourceManagerServiceNew::getLowestPriorityProcessBiggestClient_l(
        const ResourceRequestInfo& resourceRequestInfo,
        const std::vector<ClientInfo>& clients,
        ClientInfo& clientInfo) {
    int callingPid = resourceRequestInfo.mCallingPid;
    MediaResource::Type type = resourceRequestInfo.mResource->type;
    MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
    int lowestPriorityPid;
    int lowestPriority;
    int callingPriority;

    if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
        ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
        return false;
    }

    // Find the lowest priority process among all the clients.
    if (!mResourceTracker->getLowestPriorityPid(clients, lowestPriorityPid, lowestPriority)) {
        ALOGE("%s: can't find a process with lower priority than that of the process[%d:%d]",
              __func__, callingPid, callingPriority);
        return false;
    }

    if (lowestPriority <= callingPriority) {
        ALOGE("%s: lowest priority %d vs caller priority %d",
              __func__, lowestPriority, callingPriority);
        return false;
    }

    // Get the biggest client from this process.
    if (!mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType, clientInfo)) {
        return false;
    }

    ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
          __func__, callingPid, callingPriority, lowestPriorityPid, lowestPriority);
    return true;
}

bool ResourceManagerServiceNew::getLowestPriorityBiggestClient_l(
        const ResourceRequestInfo& resourceRequestInfo,
        ClientInfo& clientInfo) {
@@ -323,11 +287,25 @@ bool ResourceManagerServiceNew::getLowestPriorityBiggestClient_l(
    if (resourceRequestInfo.mResource == nullptr) {
        return false;
    }

    // Use the DefaultResourceModel to get all the clients with the resources requested.
    std::vector<MediaResourceParcel> resources{*resourceRequestInfo.mResource};
    ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, resources};
    std::vector<ClientInfo> clients;
    mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients);
    return getLowestPriorityProcessBiggestClient_l(resourceRequestInfo, clients, clientInfo);

    // Use the ProcessPriorityReclaimPolicy to select a client to reclaim from.
    std::unique_ptr<IReclaimPolicy> reclaimPolicy
        = std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker);
    std::vector<ClientInfo> targetClients;
    if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
        if (!targetClients.empty()) {
            clientInfo = targetClients[0];
            return true;
        }
    }

    return false;
}

bool ResourceManagerServiceNew::getPriority_l(int pid, int* priority) const {
Loading