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

Commit a960d1d9 authored by Chong Zhang's avatar Chong Zhang
Browse files

transcoding: add thermal status listener

Register thermal status listener with thermal manager, and
pause/resume transcoding activity when thermal status goes
above certain threshold (currently set at CRITICAL).

Add unit tests with mock thermal policy. Also add unit test
that exercise the actual transcoding service, but use adb
shell cmd to fake thermal status change.

bug: 169452730
test: unit testing added in the CL; manual testing using
"adb shell cmd thermalservice override-status #" and observe
thermal throttling logs from transcoding service.

Change-Id: I7d28ed3069bdd73e8984ad138e2edba9c9a2360a
parent bfebb60d
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -71,11 +71,12 @@ cc_library {
    ],

    srcs: [
        "TranscoderWrapper.cpp",
        "TranscodingClientManager.cpp",
        "TranscodingSessionController.cpp",
        "TranscodingResourcePolicy.cpp",
        "TranscodingSessionController.cpp",
        "TranscodingThermalPolicy.cpp",
        "TranscodingUidPolicy.cpp",
        "TranscoderWrapper.cpp",
    ],

    shared_libs: [
+53 −9
Original line number Diff line number Diff line
@@ -63,10 +63,12 @@ const char* TranscodingSessionController::sessionStateToString(const Session::St
TranscodingSessionController::TranscodingSessionController(
        const std::shared_ptr<TranscoderInterface>& transcoder,
        const std::shared_ptr<UidPolicyInterface>& uidPolicy,
        const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy)
        const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy,
        const std::shared_ptr<ThermalPolicyInterface>& thermalPolicy)
      : mTranscoder(transcoder),
        mUidPolicy(uidPolicy),
        mResourcePolicy(resourcePolicy),
        mThermalPolicy(thermalPolicy),
        mCurrentSession(nullptr),
        mResourceLost(false) {
    // Only push empty offline queue initially. Realtime queues are added when requests come in.
@@ -74,6 +76,7 @@ TranscodingSessionController::TranscodingSessionController(
    mOfflineUidIterator = mUidSortedList.begin();
    mSessionQueues.emplace(OFFLINE_UID, SessionQueueType());
    mUidPackageNames[OFFLINE_UID] = "(offline)";
    mThermalThrottling = thermalPolicy->getThrottlingStatus();
}

TranscodingSessionController::~TranscodingSessionController() {}
@@ -192,18 +195,27 @@ void TranscodingSessionController::updateCurrentSession_l() {
          topSession == nullptr ? "null" : sessionToString(topSession->key).c_str(),
          curSession == nullptr ? "null" : sessionToString(curSession->key).c_str());

    if (topSession == nullptr) {
        mCurrentSession = nullptr;
        return;
    }

    bool shouldBeRunning = !((mResourcePolicy != nullptr && mResourceLost) ||
                             (mThermalPolicy != nullptr && mThermalThrottling));
    // If we found a topSession that should be run, and it's not already running,
    // take some actions to ensure it's running.
    if (topSession != nullptr &&
        (topSession != curSession || topSession->getState() != Session::RUNNING)) {
        // If another session is currently running, pause it first.
    if (topSession != curSession ||
        (shouldBeRunning ^ (topSession->getState() == Session::RUNNING))) {
        // If current session is running, pause it first. Note this is true for either
        // cases: 1) If top session is changing, or 2) if top session is not changing but
        // the topSession's state is changing.
        if (curSession != nullptr && curSession->getState() == Session::RUNNING) {
            mTranscoder->pause(curSession->key.first, curSession->key.second);
            curSession->setState(Session::PAUSED);
        }
        // If we are not experiencing resource loss, we can start or resume
        // the topSession now.
        if (!mResourceLost) {
        // If we are not experiencing resource loss nor thermal throttling, we can start
        // or resume the topSession now.
        if (shouldBeRunning) {
            if (topSession->getState() == Session::NOT_STARTED) {
                mTranscoder->start(topSession->key.first, topSession->key.second,
                                   topSession->request, topSession->callback.lock());
@@ -566,7 +578,9 @@ void TranscodingSessionController::onResourceLost(ClientIdType clientId, Session
        if (clientCallback != nullptr) {
            clientCallback->onTranscodingPaused(sessionKey.second);
        }
        if (mResourcePolicy != nullptr) {
            mResourcePolicy->setPidResourceLost(resourceLostSession->request.clientPid);
        }
        mResourceLost = true;

        validateState_l();
@@ -613,6 +627,36 @@ void TranscodingSessionController::onResourceAvailable() {
    validateState_l();
}

void TranscodingSessionController::onThrottlingStarted() {
    std::scoped_lock lock{mLock};

    if (mThermalThrottling) {
        return;
    }

    ALOGI("%s", __FUNCTION__);

    mThermalThrottling = true;
    updateCurrentSession_l();

    validateState_l();
}

void TranscodingSessionController::onThrottlingStopped() {
    std::scoped_lock lock{mLock};

    if (!mThermalThrottling) {
        return;
    }

    ALOGI("%s", __FUNCTION__);

    mThermalThrottling = false;
    updateCurrentSession_l();

    validateState_l();
}

void TranscodingSessionController::validateState_l() {
#ifdef VALIDATE_STATE
    LOG_ALWAYS_FATAL_IF(mSessionQueues.count(OFFLINE_UID) != 1,
+125 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 "TranscodingThermalPolicy"

#include <media/TranscodingThermalPolicy.h>
#include <utils/Log.h>

namespace android {

static bool needThrottling(AThermalStatus status) {
    return (status >= ATHERMAL_STATUS_SEVERE);
}

//static
void TranscodingThermalPolicy::onStatusChange(void* data, AThermalStatus status) {
    TranscodingThermalPolicy* policy = static_cast<TranscodingThermalPolicy*>(data);
    policy->onStatusChange(status);
}

TranscodingThermalPolicy::TranscodingThermalPolicy()
      : mRegistered(false), mThermalManager(nullptr), mIsThrottling(false) {
    registerSelf();
}

TranscodingThermalPolicy::~TranscodingThermalPolicy() {
    unregisterSelf();
}

void TranscodingThermalPolicy::registerSelf() {
    ALOGI("TranscodingThermalPolicy: registerSelf");

    std::scoped_lock lock{mRegisteredLock};

    if (mRegistered) {
        return;
    }

    AThermalManager* thermalManager = AThermal_acquireManager();
    if (thermalManager == nullptr) {
        ALOGE("Failed to acquire thermal manager");
        return;
    }

    int ret = AThermal_registerThermalStatusListener(thermalManager, onStatusChange, this);
    if (ret != 0) {
        ALOGE("Failed to register thermal status listener");
        AThermal_releaseManager(thermalManager);
        return;
    }

    mIsThrottling = needThrottling(AThermal_getCurrentThermalStatus(thermalManager));
    mThermalManager = thermalManager;
    mRegistered = true;
}

void TranscodingThermalPolicy::unregisterSelf() {
    ALOGI("TranscodingThermalPolicy: unregisterSelf");

    std::scoped_lock lock{mRegisteredLock};

    if (!mRegistered) {
        return;
    }

    if (mThermalManager != nullptr) {
        // Unregister listener
        int ret = AThermal_unregisterThermalStatusListener(mThermalManager, onStatusChange, this);
        if (ret != 0) {
            ALOGW("Failed to unregister thermal status listener");
        }
        AThermal_releaseManager(mThermalManager);
        mThermalManager = nullptr;
    }
    mRegistered = false;
}

void TranscodingThermalPolicy::setCallback(
        const std::shared_ptr<ThermalPolicyCallbackInterface>& cb) {
    std::scoped_lock lock{mCallbackLock};
    mThermalPolicyCallback = cb;
}

bool TranscodingThermalPolicy::getThrottlingStatus() {
    std::scoped_lock lock{mRegisteredLock};
    return mIsThrottling;
}

void TranscodingThermalPolicy::onStatusChange(AThermalStatus status) {
    bool isThrottling = needThrottling(status);

    {
        std::scoped_lock lock{mRegisteredLock};
        if (isThrottling == mIsThrottling) {
            return;
        }
        ALOGI("Transcoding thermal throttling changed: %d", isThrottling);
        mIsThrottling = isThrottling;
    }

    std::scoped_lock lock{mCallbackLock};
    std::shared_ptr<ThermalPolicyCallbackInterface> cb;
    if ((cb = mThermalPolicyCallback.lock()) != nullptr) {
        if (isThrottling) {
            cb->onThrottlingStarted();
        } else {
            cb->onThrottlingStopped();
        }
    }
}
}  // namespace android
+5 −11
Original line number Diff line number Diff line
@@ -32,9 +32,7 @@ constexpr static uid_t OFFLINE_UID = -1;
constexpr static int32_t IMPORTANCE_UNKNOWN = INT32_MAX;

TranscodingUidPolicy::TranscodingUidPolicy()
      : mUidObserver(nullptr),
        mRegistered(false),
        mTopUidState(IMPORTANCE_UNKNOWN) {
      : mUidObserver(nullptr), mRegistered(false), mTopUidState(IMPORTANCE_UNKNOWN) {
    registerSelf();
}

@@ -129,8 +127,7 @@ void TranscodingUidPolicy::unregisterMonitorUid(uid_t uid) {
bool TranscodingUidPolicy::isUidOnTop(uid_t uid) {
    Mutex::Autolock _l(mUidLock);

    return mTopUidState != IMPORTANCE_UNKNOWN &&
           mTopUidState == getProcState_l(uid);
    return mTopUidState != IMPORTANCE_UNKNOWN && mTopUidState == getProcState_l(uid);
}

std::unordered_set<uid_t> TranscodingUidPolicy::getTopUids() const {
@@ -155,12 +152,10 @@ void TranscodingUidPolicy::onUidStateChanged(uid_t uid, int32_t procState) {
            // Top set changed if 1) the uid is in the current top uid set, or 2) the
            // new procState is at least the same priority as the current top uid state.
            bool isUidCurrentTop =
                    mTopUidState != IMPORTANCE_UNKNOWN &&
                    mStateUidMap[mTopUidState].count(uid) > 0;
                    mTopUidState != IMPORTANCE_UNKNOWN && mStateUidMap[mTopUidState].count(uid) > 0;
            bool isNewStateHigherThanTop =
                    procState != IMPORTANCE_UNKNOWN &&
                    (procState <= mTopUidState ||
                     mTopUidState == IMPORTANCE_UNKNOWN);
                    (procState <= mTopUidState || mTopUidState == IMPORTANCE_UNKNOWN);
            topUidSetChanged = (isUidCurrentTop || isNewStateHigherThanTop);

            // Move uid to the new procState.
@@ -192,8 +187,7 @@ void TranscodingUidPolicy::updateTopUid_l() {

    // Find the lowest uid state (ignoring PROCESS_STATE_UNKNOWN) with some monitored uids.
    for (auto stateIt = mStateUidMap.begin(); stateIt != mStateUidMap.end(); stateIt++) {
        if (stateIt->first != IMPORTANCE_UNKNOWN &&
            !stateIt->second.empty()) {
        if (stateIt->first != IMPORTANCE_UNKNOWN && !stateIt->second.empty()) {
            mTopUidState = stateIt->first;
            break;
        }
+52 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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_THERMAL_POLICY_INTERFACE_H
#define ANDROID_MEDIA_THERMAL_POLICY_INTERFACE_H
#include <memory>

namespace android {

class ThermalPolicyCallbackInterface;

// Interface for the SessionController to control the thermal policy.
class ThermalPolicyInterface {
public:
    // Set the associated callback interface to send the events when the thermal
    // status changes.
    virtual void setCallback(const std::shared_ptr<ThermalPolicyCallbackInterface>& cb) = 0;

    // Get the current thermal throttling status. Returns true if throttling is on,
    // false otherwise.
    virtual bool getThrottlingStatus() = 0;

protected:
    virtual ~ThermalPolicyInterface() = default;
};

// Interface for notifying the SessionController of thermal throttling status.
class ThermalPolicyCallbackInterface {
public:
    // Called when the session controller should start or stop thermal throttling.
    virtual void onThrottlingStarted() = 0;
    virtual void onThrottlingStopped() = 0;

protected:
    virtual ~ThermalPolicyCallbackInterface() = default;
};

}  // namespace android
#endif  // ANDROID_MEDIA_THERMAL_POLICY_INTERFACE_H
Loading