| /* |
| * Copyright 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_TAG "powerhal-libperfmgr" |
| #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL) |
| |
| #include "PowerSessionManager.h" |
| |
| #include <android-base/file.h> |
| #include <android-base/stringprintf.h> |
| #include <log/log.h> |
| #include <perfmgr/HintManager.h> |
| #include <private/android_filesystem_config.h> |
| #include <processgroup/processgroup.h> |
| #include <sys/syscall.h> |
| #include <utils/Trace.h> |
| |
| #include "AdpfTypes.h" |
| #include "AppDescriptorTrace.h" |
| #include "AppHintDesc.h" |
| #include "tests/mocks/MockHintManager.h" |
| |
| namespace aidl { |
| namespace google { |
| namespace hardware { |
| namespace power { |
| namespace impl { |
| namespace pixel { |
| |
| using ::android::perfmgr::HintManager; |
| |
| namespace { |
| /* there is no glibc or bionic wrapper */ |
| struct sched_attr { |
| __u32 size; |
| __u32 sched_policy; |
| __u64 sched_flags; |
| __s32 sched_nice; |
| __u32 sched_priority; |
| __u64 sched_runtime; |
| __u64 sched_deadline; |
| __u64 sched_period; |
| __u32 sched_util_min; |
| __u32 sched_util_max; |
| }; |
| |
| static int set_uclamp(int tid, UclampRange range) { |
| // Ensure min and max are bounded by the range limits and each other |
| range.uclampMin = std::min(std::max(kUclampMin, range.uclampMin), kUclampMax); |
| range.uclampMax = std::min(std::max(range.uclampMax, range.uclampMin), kUclampMax); |
| sched_attr attr = {}; |
| attr.size = sizeof(attr); |
| |
| attr.sched_flags = |
| (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN | SCHED_FLAG_UTIL_CLAMP_MAX); |
| attr.sched_util_min = range.uclampMin; |
| attr.sched_util_max = range.uclampMax; |
| |
| const int ret = syscall(__NR_sched_setattr, tid, attr, 0); |
| if (ret) { |
| ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno); |
| return errno; |
| } |
| return 0; |
| } |
| } // namespace |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::updateHintMode(const std::string &mode, bool enabled) { |
| if (enabled && mode.compare(0, 8, "REFRESH_") == 0) { |
| if (mode.compare("REFRESH_120FPS") == 0) { |
| mDisplayRefreshRate = 120; |
| } else if (mode.compare("REFRESH_90FPS") == 0) { |
| mDisplayRefreshRate = 90; |
| } else if (mode.compare("REFRESH_60FPS") == 0) { |
| mDisplayRefreshRate = 60; |
| } |
| } |
| if (HintManager::GetInstance()->GetAdpfProfile()) { |
| HintManager::GetInstance()->SetAdpfProfile(mode); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::updateHintBoost(const std::string &boost, |
| int32_t durationMs) { |
| ATRACE_CALL(); |
| ALOGV("PowerSessionManager::updateHintBoost: boost: %s, durationMs: %d", boost.c_str(), |
| durationMs); |
| } |
| |
| template <class HintManagerT> |
| int PowerSessionManager<HintManagerT>::getDisplayRefreshRate() { |
| return mDisplayRefreshRate; |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::addPowerSession( |
| const std::string &idString, const std::shared_ptr<AppHintDesc> &sessionDescriptor, |
| const std::shared_ptr<AppDescriptorTrace> &sessionTrace, |
| const std::vector<int32_t> &threadIds) { |
| if (!sessionDescriptor) { |
| ALOGE("sessionDescriptor is null. PowerSessionManager failed to add power session: %s", |
| idString.c_str()); |
| return; |
| } |
| const auto timeNow = std::chrono::steady_clock::now(); |
| SessionValueEntry sve; |
| sve.tgid = sessionDescriptor->tgid; |
| sve.uid = sessionDescriptor->uid; |
| sve.idString = idString; |
| sve.isActive = sessionDescriptor->is_active; |
| sve.isAppSession = sessionDescriptor->uid >= AID_APP_START; |
| sve.lastUpdatedTime = timeNow; |
| sve.votes = std::make_shared<Votes>(); |
| sve.sessionTrace = sessionTrace; |
| sve.votes->add( |
| static_cast<std::underlying_type_t<AdpfVoteType>>(AdpfVoteType::CPU_VOTE_DEFAULT), |
| CpuVote(false, timeNow, sessionDescriptor->targetNs, kUclampMin, kUclampMax)); |
| |
| bool addedRes = false; |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| addedRes = mSessionTaskMap.add(sessionDescriptor->sessionId, sve, {}); |
| } |
| if (!addedRes) { |
| ALOGE("sessionTaskMap failed to add power session: %" PRId64, sessionDescriptor->sessionId); |
| } |
| |
| setThreadsFromPowerSession(sessionDescriptor->sessionId, threadIds); |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::removePowerSession(int64_t sessionId) { |
| // To remove a session we also need to undo the effects the session |
| // has on currently enabled votes which means setting vote to inactive |
| // and then forceing a uclamp update to occur |
| forceSessionActive(sessionId, false); |
| |
| std::vector<pid_t> addedThreads; |
| std::vector<pid_t> removedThreads; |
| |
| { |
| // Wait till end to remove session because it needs to be around for apply U clamp |
| // to work above since applying the uclamp needs a valid session id |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| mSessionTaskMap.replace(sessionId, {}, &addedThreads, &removedThreads); |
| mSessionTaskMap.remove(sessionId); |
| } |
| |
| for (auto tid : removedThreads) { |
| if (!SetTaskProfiles(tid, {"NoResetUclampGrp"})) { |
| ALOGE("Failed to set NoResetUclampGrp task profile for tid:%d", tid); |
| } |
| } |
| |
| unregisterSession(sessionId); |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::setThreadsFromPowerSession( |
| int64_t sessionId, const std::vector<int32_t> &threadIds) { |
| std::vector<pid_t> addedThreads; |
| std::vector<pid_t> removedThreads; |
| forceSessionActive(sessionId, false); |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| mSessionTaskMap.replace(sessionId, threadIds, &addedThreads, &removedThreads); |
| } |
| for (auto tid : addedThreads) { |
| if (!SetTaskProfiles(tid, {"ResetUclampGrp"})) { |
| ALOGE("Failed to set ResetUclampGrp task profile for tid:%d", tid); |
| } |
| } |
| for (auto tid : removedThreads) { |
| if (!SetTaskProfiles(tid, {"NoResetUclampGrp"})) { |
| ALOGE("Failed to set NoResetUclampGrp task profile for tid:%d", tid); |
| } |
| } |
| forceSessionActive(sessionId, true); |
| } |
| |
| template <class HintManagerT> |
| std::optional<bool> PowerSessionManager<HintManagerT>::isAnyAppSessionActive() { |
| bool isAnyAppSessionActive = false; |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| isAnyAppSessionActive = |
| mSessionTaskMap.isAnyAppSessionActive(std::chrono::steady_clock::now()); |
| } |
| return isAnyAppSessionActive; |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::updateUniversalBoostMode() { |
| const auto active = isAnyAppSessionActive(); |
| if (!active.has_value()) { |
| return; |
| } |
| if (active.value()) { |
| disableSystemTopAppBoost(); |
| } else { |
| enableSystemTopAppBoost(); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::dumpToFd(int fd) { |
| std::ostringstream dump_buf; |
| dump_buf << "========== Begin PowerSessionManager ADPF list ==========\n"; |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| mSessionTaskMap.forEachSessionValTasks( |
| [&](auto /* sessionId */, const auto &sessionVal, const auto &tasks) { |
| sessionVal.dump(dump_buf); |
| dump_buf << " Tid:Ref["; |
| |
| size_t tasksLen = tasks.size(); |
| for (auto taskId : tasks) { |
| dump_buf << taskId << ":"; |
| const auto &sessionIds = mSessionTaskMap.getSessionIds(taskId); |
| if (!sessionIds.empty()) { |
| dump_buf << sessionIds.size(); |
| } |
| if (tasksLen > 0) { |
| dump_buf << ", "; |
| --tasksLen; |
| } |
| } |
| dump_buf << "]\n"; |
| }); |
| dump_buf << "========== End PowerSessionManager ADPF list ==========\n"; |
| if (!::android::base::WriteStringToFd(dump_buf.str(), fd)) { |
| ALOGE("Failed to dump one of session list to fd:%d", fd); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::pause(int64_t sessionId) { |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| auto sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (nullptr == sessValPtr) { |
| ALOGW("Pause failed, session is null %" PRId64, sessionId); |
| return; |
| } |
| |
| if (!sessValPtr->isActive) { |
| ALOGW("Sess(%" PRId64 "), cannot pause, already inActive", sessionId); |
| return; |
| } |
| sessValPtr->isActive = false; |
| } |
| applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now()); |
| updateUniversalBoostMode(); |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::resume(int64_t sessionId) { |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| auto sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (nullptr == sessValPtr) { |
| ALOGW("Resume failed, session is null %" PRId64, sessionId); |
| return; |
| } |
| |
| if (sessValPtr->isActive) { |
| ALOGW("Sess(%" PRId64 "), cannot resume, already active", sessionId); |
| return; |
| } |
| sessValPtr->isActive = true; |
| } |
| applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now()); |
| updateUniversalBoostMode(); |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::updateTargetWorkDuration( |
| int64_t sessionId, AdpfVoteType voteId, std::chrono::nanoseconds durationNs) { |
| int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId); |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| auto sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (nullptr == sessValPtr) { |
| ALOGE("Failed to updateTargetWorkDuration, session val is null id: %" PRId64, sessionId); |
| return; |
| } |
| |
| sessValPtr->votes->updateDuration(voteIdInt, durationNs); |
| // Note, for now we are not recalculating and applying uclamp because |
| // that maintains behavior from before. In the future we may want to |
| // revisit that decision. |
| } |
| |
| template <typename T> |
| auto shouldScheduleTimeout(Votes const &votes, int vote_id, std::chrono::time_point<T> deadline) |
| -> bool { |
| return !votes.voteIsActive(vote_id) || deadline < votes.voteTimeout(vote_id); |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::voteSet(int64_t sessionId, AdpfVoteType voteId, |
| int uclampMin, int uclampMax, |
| std::chrono::steady_clock::time_point startTime, |
| std::chrono::nanoseconds durationNs) { |
| const int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId); |
| const auto timeoutDeadline = startTime + durationNs; |
| bool scheduleTimeout = false; |
| |
| { |
| std::lock_guard lock(mSessionTaskMapMutex); |
| auto session = mSessionTaskMap.findSession(sessionId); |
| if (!session) { |
| // Because of the async nature of some events an event for a session |
| // that has been removed is a possibility |
| return; |
| } |
| scheduleTimeout = shouldScheduleTimeout(*session->votes, voteIdInt, timeoutDeadline), |
| mSessionTaskMap.addVote(sessionId, voteIdInt, uclampMin, uclampMax, startTime, durationNs); |
| if (ATRACE_ENABLED()) { |
| ATRACE_INT(session->sessionTrace->trace_votes[voteIdInt].c_str(), uclampMin); |
| } |
| session->lastUpdatedTime = startTime; |
| applyUclampLocked(sessionId, startTime); |
| } |
| |
| if (scheduleTimeout) { |
| mEventSessionTimeoutWorker.schedule( |
| {.timeStamp = startTime, .sessionId = sessionId, .voteId = voteIdInt}, |
| timeoutDeadline); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::voteSet(int64_t sessionId, AdpfVoteType voteId, |
| Cycles capacity, |
| std::chrono::steady_clock::time_point startTime, |
| std::chrono::nanoseconds durationNs) { |
| const int voteIdInt = static_cast<std::underlying_type_t<AdpfVoteType>>(voteId); |
| const auto timeoutDeadline = startTime + durationNs; |
| bool scheduleTimeout = false; |
| |
| { |
| std::lock_guard lock(mSessionTaskMapMutex); |
| auto session = mSessionTaskMap.findSession(sessionId); |
| if (!session) { |
| return; |
| } |
| scheduleTimeout = shouldScheduleTimeout(*session->votes, voteIdInt, timeoutDeadline), |
| mSessionTaskMap.addGpuVote(sessionId, voteIdInt, capacity, startTime, durationNs); |
| if (ATRACE_ENABLED()) { |
| ATRACE_INT(session->sessionTrace->trace_votes[voteIdInt].c_str(), |
| static_cast<int>(capacity)); |
| } |
| session->lastUpdatedTime = startTime; |
| applyGpuVotesLocked(sessionId, startTime); |
| } |
| |
| if (scheduleTimeout) { |
| mEventSessionTimeoutWorker.schedule( |
| {.timeStamp = startTime, .sessionId = sessionId, .voteId = voteIdInt}, |
| timeoutDeadline); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::disableBoosts(int64_t sessionId) { |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| auto sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (nullptr == sessValPtr) { |
| // Because of the async nature of some events an event for a session |
| // that has been removed is a possibility |
| return; |
| } |
| |
| // sessValPtr->disableBoosts(); |
| for (auto vid : {AdpfVoteType::CPU_LOAD_UP, AdpfVoteType::CPU_LOAD_RESET, |
| AdpfVoteType::CPU_LOAD_RESUME, AdpfVoteType::VOTE_POWER_EFFICIENCY, |
| AdpfVoteType::GPU_LOAD_UP, AdpfVoteType::GPU_LOAD_RESET}) { |
| auto vint = static_cast<std::underlying_type_t<AdpfVoteType>>(vid); |
| sessValPtr->votes->setUseVote(vint, false); |
| if (ATRACE_ENABLED()) { |
| ATRACE_INT(sessValPtr->sessionTrace->trace_votes[vint].c_str(), 0); |
| } |
| } |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::enableSystemTopAppBoost() { |
| if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) { |
| ALOGV("PowerSessionManager::enableSystemTopAppBoost!!"); |
| HintManager::GetInstance()->EndHint(kDisableBoostHintName); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::disableSystemTopAppBoost() { |
| if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) { |
| ALOGV("PowerSessionManager::disableSystemTopAppBoost!!"); |
| HintManager::GetInstance()->DoHint(kDisableBoostHintName); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::handleEvent(const EventSessionTimeout &eventTimeout) { |
| bool recalcUclamp = false; |
| const auto tNow = std::chrono::steady_clock::now(); |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| auto sessValPtr = mSessionTaskMap.findSession(eventTimeout.sessionId); |
| if (nullptr == sessValPtr) { |
| // It is ok for session timeouts to fire after a session has been |
| // removed |
| return; |
| } |
| |
| // To minimize the number of events pushed into the queue, we are using |
| // the following logic to make use of a single timeout event which will |
| // requeue itself if the timeout has been changed since it was added to |
| // the work queue. Requeue Logic: |
| // if vote active and vote timeout <= sched time |
| // then deactivate vote and recalc uclamp (near end of function) |
| // if vote active and vote timeout > sched time |
| // then requeue timeout event for new deadline (which is vote timeout) |
| const bool voteIsActive = sessValPtr->votes->voteIsActive(eventTimeout.voteId); |
| const auto voteTimeout = sessValPtr->votes->voteTimeout(eventTimeout.voteId); |
| |
| if (voteIsActive) { |
| if (voteTimeout <= tNow) { |
| sessValPtr->votes->setUseVote(eventTimeout.voteId, false); |
| recalcUclamp = true; |
| if (ATRACE_ENABLED()) { |
| ATRACE_INT(sessValPtr->sessionTrace->trace_votes[eventTimeout.voteId].c_str(), |
| 0); |
| } |
| } else { |
| // Can unlock sooner than we do |
| auto eventTimeout2 = eventTimeout; |
| mEventSessionTimeoutWorker.schedule(eventTimeout2, voteTimeout); |
| } |
| } |
| } |
| |
| if (!recalcUclamp) { |
| return; |
| } |
| |
| // It is important to use the correct time here, time now is more reasonable |
| // than trying to use the event's timestamp which will be slightly off given |
| // the background priority queue introduces latency |
| applyCpuAndGpuVotes(eventTimeout.sessionId, tNow); |
| updateUniversalBoostMode(); |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::applyUclampLocked( |
| int64_t sessionId, std::chrono::steady_clock::time_point timePoint) { |
| auto config = HintManager::GetInstance()->GetAdpfProfile(); |
| { |
| // TODO(kevindubois) un-indent this in followup patch to reduce churn. |
| auto sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (nullptr == sessValPtr) { |
| return; |
| } |
| |
| if (!config->mUclampMinOn) { |
| ALOGV("PowerSessionManager::set_uclamp: skip"); |
| } else { |
| auto &threadList = mSessionTaskMap.getTaskIds(sessionId); |
| auto tidIter = threadList.begin(); |
| while (tidIter != threadList.end()) { |
| UclampRange uclampRange; |
| mSessionTaskMap.getTaskVoteRange(*tidIter, timePoint, uclampRange, |
| config->mUclampMaxEfficientBase, |
| config->mUclampMaxEfficientOffset); |
| int stat = set_uclamp(*tidIter, uclampRange); |
| if (stat == ESRCH) { |
| ALOGV("Removing dead thread %d from hint session %s.", *tidIter, |
| sessValPtr->idString.c_str()); |
| if (mSessionTaskMap.removeDeadTaskSessionMap(sessionId, *tidIter)) { |
| ALOGV("Removed dead thread-session map."); |
| } |
| tidIter = threadList.erase(tidIter); |
| } else { |
| tidIter++; |
| } |
| } |
| } |
| |
| sessValPtr->lastUpdatedTime = timePoint; |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::applyGpuVotesLocked( |
| int64_t sessionId, std::chrono::steady_clock::time_point timePoint) { |
| auto const sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (!sessValPtr) { |
| return; |
| } |
| |
| auto const gpuVotingOn = HintManager::GetInstance()->GetAdpfProfile()->mGpuBoostOn; |
| if (mGpuCapacityNode && gpuVotingOn) { |
| auto const capacity = mSessionTaskMap.getSessionsGpuCapacity(timePoint); |
| (*mGpuCapacityNode)->set_gpu_capacity(capacity); |
| } |
| |
| sessValPtr->lastUpdatedTime = timePoint; |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::applyCpuAndGpuVotes( |
| int64_t sessionId, std::chrono::steady_clock::time_point timePoint) { |
| std::lock_guard lock(mSessionTaskMapMutex); |
| applyUclampLocked(sessionId, timePoint); |
| applyGpuVotesLocked(sessionId, timePoint); |
| } |
| |
| template <class HintManagerT> |
| std::optional<Frequency> PowerSessionManager<HintManagerT>::gpuFrequency() const { |
| if (mGpuCapacityNode) { |
| return (*mGpuCapacityNode)->gpu_frequency(); |
| } |
| return {}; |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::forceSessionActive(int64_t sessionId, bool isActive) { |
| { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| auto sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (nullptr == sessValPtr) { |
| return; |
| } |
| sessValPtr->isActive = isActive; |
| } |
| |
| // As currently written, call needs to occur synchronously so as to ensure |
| // that the SessionId remains valid and mapped to the proper threads/tasks |
| // which enables apply u clamp to work correctly |
| applyCpuAndGpuVotes(sessionId, std::chrono::steady_clock::now()); |
| updateUniversalBoostMode(); |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::setPreferPowerEfficiency(int64_t sessionId, bool enabled) { |
| std::lock_guard<std::mutex> lock(mSessionTaskMapMutex); |
| auto sessValPtr = mSessionTaskMap.findSession(sessionId); |
| if (nullptr == sessValPtr) { |
| return; |
| } |
| if (enabled != sessValPtr->isPowerEfficient) { |
| sessValPtr->isPowerEfficient = enabled; |
| applyUclampLocked(sessionId, std::chrono::steady_clock::now()); |
| } |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::registerSession(std::shared_ptr<void> session, |
| int64_t sessionId) { |
| std::lock_guard<std::mutex> lock(mSessionMapMutex); |
| mSessionMap[sessionId] = session; |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::unregisterSession(int64_t sessionId) { |
| std::lock_guard<std::mutex> lock(mSessionMapMutex); |
| mSessionMap.erase(sessionId); |
| } |
| |
| template <class HintManagerT> |
| std::shared_ptr<void> PowerSessionManager<HintManagerT>::getSession(int64_t sessionId) { |
| std::scoped_lock lock(mSessionMapMutex); |
| auto ptr = mSessionMap.find(sessionId); |
| if (ptr == mSessionMap.end()) { |
| return nullptr; |
| } |
| std::shared_ptr<void> out = ptr->second.lock(); |
| if (!out) { |
| mSessionMap.erase(sessionId); |
| return nullptr; |
| } |
| return out; |
| } |
| |
| template <class HintManagerT> |
| void PowerSessionManager<HintManagerT>::clear() { |
| std::scoped_lock lock(mSessionMapMutex); |
| mSessionMap.clear(); |
| } |
| |
| template class PowerSessionManager<>; |
| template class PowerSessionManager<testing::NiceMock<mock::pixel::MockHintManager>>; |
| |
| } // namespace pixel |
| } // namespace impl |
| } // namespace power |
| } // namespace hardware |
| } // namespace google |
| } // namespace aidl |