1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <algorithm>
16 #include "rs_frame_rate_vote.h"
17 #include "hgm_core.h"
18 #include "platform/common/rs_log.h"
19 #include "sandbox_utils.h"
20 
21 namespace OHOS {
22 namespace Rosen {
23 namespace {
24     const std::string VIDEO_RATE_FLAG = "VIDEO_RATE";
25     const std::string VIDEO_VOTE_FLAG = "VOTER_VIDEO";
26 }
27 
RSFrameRateVote()28 RSFrameRateVote::RSFrameRateVote()
29 {
30     frameRateMgr_ = OHOS::Rosen::HgmCore::Instance().GetFrameRateMgr();
31     ffrtQueue_ = std::make_shared<ffrt::queue>("frame_rate_vote_queue");
32     auto policyConfigData = OHOS::Rosen::HgmCore::Instance().GetPolicyConfigData();
33     if (policyConfigData != nullptr) {
34         isSwitchOn_ = policyConfigData->videoFrameRateVoteSwitch_;
35         RS_LOGI("video vote feature isSwitchOn:%{public}s", isSwitchOn_ ? "true" : "false");
36     }
37 }
38 
~RSFrameRateVote()39 RSFrameRateVote::~RSFrameRateVote()
40 {
41     frameRateMgr_ = nullptr;
42     ffrtQueue_ = nullptr;
43 }
44 
VideoFrameRateVote(uint64_t surfaceNodeId,OHSurfaceSource sourceType,sptr<SurfaceBuffer> & buffer)45 void RSFrameRateVote::VideoFrameRateVote(uint64_t surfaceNodeId, OHSurfaceSource sourceType,
46     sptr<SurfaceBuffer>& buffer)
47 {
48     if (!isSwitchOn_ || sourceType != OHSurfaceSource::OH_SURFACE_SOURCE_VIDEO || buffer == nullptr) {
49         return;
50     }
51     double videoRate = 0.0;
52     sptr<BufferExtraData> extraData = buffer->GetExtraData();
53     if (extraData != nullptr) {
54         extraData->ExtraGet(VIDEO_RATE_FLAG, videoRate);
55     }
56     std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
57     auto initTask = [this, surfaceNodeId, videoRate]() {
58         std::shared_ptr<RSVideoFrameRateVote> rsVideoFrameRateVote;
59         if (surfaceVideoFrameRateVote_.find(surfaceNodeId) == surfaceVideoFrameRateVote_.end()) {
60             rsVideoFrameRateVote = std::make_shared<RSVideoFrameRateVote>(surfaceNodeId,
61                 [this](uint64_t id) { this->ReleaseSurfaceMap(id); },
62                 [this](uint64_t id, uint32_t rate) { this->SurfaceVideoVote(id, rate); });
63             surfaceVideoFrameRateVote_.insert(std::pair<uint64_t, std::shared_ptr<RSVideoFrameRateVote>>(
64                 surfaceNodeId, rsVideoFrameRateVote));
65         } else {
66             rsVideoFrameRateVote = surfaceVideoFrameRateVote_[surfaceNodeId];
67         }
68         rsVideoFrameRateVote->StartVideoFrameRateVote(videoRate);
69     };
70     if (ffrtQueue_) {
71         ffrtQueue_->submit(initTask);
72     }
73 }
74 
ReleaseSurfaceMap(uint64_t surfaceNodeId)75 void RSFrameRateVote::ReleaseSurfaceMap(uint64_t surfaceNodeId)
76 {
77     std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
78     auto initTask = [this, surfaceNodeId]() {
79         SurfaceVideoVote(surfaceNodeId, 0);
80         auto it = surfaceVideoFrameRateVote_.find(surfaceNodeId);
81         if (it != surfaceVideoFrameRateVote_.end()) {
82             RS_LOGI("video vote release surfaceNodeId(%{public}s), size(%{public}d)",
83                 std::to_string(surfaceNodeId).c_str(), static_cast<int>(surfaceVideoFrameRateVote_.size()));
84             surfaceVideoFrameRateVote_.erase(it);
85         }
86     };
87     if (ffrtQueue_) {
88         ffrtQueue_->submit(initTask);
89     }
90 }
91 
SurfaceVideoVote(uint64_t surfaceNodeId,uint32_t rate)92 void RSFrameRateVote::SurfaceVideoVote(uint64_t surfaceNodeId, uint32_t rate)
93 {
94     std::lock_guard<std::mutex> lock(mutex_);
95     if (rate == 0) {
96         auto it = surfaceVideoRate_.find(surfaceNodeId);
97         if (it != surfaceVideoRate_.end()) {
98             surfaceVideoRate_.erase(it);
99         }
100     } else {
101         surfaceVideoRate_[surfaceNodeId] = rate;
102     }
103     if (surfaceVideoRate_.size() == 0) {
104         CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
105         lastVotedPid_ = DEFAULT_PID;
106         lastVotedRate_ = OLED_NULL_HZ;
107         return;
108     }
109     auto maxElement = std::max_element(surfaceVideoRate_.begin(), surfaceVideoRate_.end(),
110         [] (const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
111     uint32_t maxRate = maxElement->second;
112     pid_t maxPid = ExtractPid(maxElement->first);
113     if (maxRate == lastVotedRate_ && maxPid == lastVotedPid_) {
114         return;
115     }
116     CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
117     VoteRate(maxPid, VIDEO_VOTE_FLAG, maxRate);
118     lastVotedPid_ = maxPid;
119     lastVotedRate_ = maxRate;
120 }
121 
VoteRate(pid_t pid,std::string eventName,uint32_t rate)122 void RSFrameRateVote::VoteRate(pid_t pid, std::string eventName, uint32_t rate)
123 {
124     isVoted_ = true;
125     EventInfo eventInfo = {
126         .eventName = eventName,
127         .eventStatus = true,
128         .minRefreshRate = rate,
129         .maxRefreshRate = rate,
130     };
131     NotifyRefreshRateEvent(pid, eventInfo);
132 }
133 
CancelVoteRate(pid_t pid,std::string eventName)134 void RSFrameRateVote::CancelVoteRate(pid_t pid, std::string eventName)
135 {
136     if (!isVoted_) {
137         return;
138     }
139     isVoted_ = false;
140     EventInfo eventInfo = {
141         .eventName = eventName,
142         .eventStatus = false,
143     };
144     NotifyRefreshRateEvent(pid, eventInfo);
145 }
146 
NotifyRefreshRateEvent(pid_t pid,EventInfo eventInfo)147 void RSFrameRateVote::NotifyRefreshRateEvent(pid_t pid, EventInfo eventInfo)
148 {
149     if (frameRateMgr_ && pid > DEFAULT_PID) {
150         RS_LOGI("video vote pid:%{public}d rate(%{public}u, %{public}u)",
151             pid, eventInfo.minRefreshRate, eventInfo.maxRefreshRate);
152         frameRateMgr_->HandleRefreshRateEvent(pid, eventInfo);
153     }
154 }
155 } // namespace Rosen
156 } // namespace OHOS