1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #undef LOG_TAG
18 #define LOG_TAG "LayerHistory"
19 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20 
21 #include "LayerHistory.h"
22 
23 #include <android-base/stringprintf.h>
24 #include <cutils/properties.h>
25 #include <utils/Log.h>
26 #include <utils/Timers.h>
27 #include <utils/Trace.h>
28 
29 #include <algorithm>
30 #include <cmath>
31 #include <string>
32 #include <utility>
33 
34 #include "../Layer.h"
35 #include "LayerInfo.h"
36 #include "SchedulerUtils.h"
37 
38 namespace android::scheduler {
39 
40 namespace {
41 
isLayerActive(const LayerInfo & info,nsecs_t threshold)42 bool isLayerActive(const LayerInfo& info, nsecs_t threshold) {
43     // Layers with an explicit vote are always kept active
44     if (info.getSetFrameRateVote().rate.isValid()) {
45         return true;
46     }
47 
48     return info.isVisible() && info.getLastUpdatedTime() >= threshold;
49 }
50 
traceEnabled()51 bool traceEnabled() {
52     return property_get_bool("debug.sf.layer_history_trace", false);
53 }
54 
useFrameRatePriority()55 bool useFrameRatePriority() {
56     char value[PROPERTY_VALUE_MAX];
57     property_get("debug.sf.use_frame_rate_priority", value, "1");
58     return atoi(value);
59 }
60 
trace(const LayerInfo & info,LayerHistory::LayerVoteType type,int fps)61 void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) {
62     const auto traceType = [&](LayerHistory::LayerVoteType checkedType, int value) {
63         ATRACE_INT(info.getTraceTag(checkedType), type == checkedType ? value : 0);
64     };
65 
66     traceType(LayerHistory::LayerVoteType::NoVote, 1);
67     traceType(LayerHistory::LayerVoteType::Heuristic, fps);
68     traceType(LayerHistory::LayerVoteType::ExplicitDefault, fps);
69     traceType(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, fps);
70     traceType(LayerHistory::LayerVoteType::ExplicitExact, fps);
71     traceType(LayerHistory::LayerVoteType::Min, 1);
72     traceType(LayerHistory::LayerVoteType::Max, 1);
73 
74     ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps);
75 }
76 } // namespace
77 
LayerHistory()78 LayerHistory::LayerHistory()
79       : mTraceEnabled(traceEnabled()), mUseFrameRatePriority(useFrameRatePriority()) {
80     LayerInfo::setTraceEnabled(mTraceEnabled);
81 }
82 
83 LayerHistory::~LayerHistory() = default;
84 
registerLayer(Layer * layer,LayerVoteType type)85 void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
86     std::lock_guard lock(mLock);
87     for (const auto& info : mLayerInfos) {
88         LOG_ALWAYS_FATAL_IF(info.first == layer, "%s already registered", layer->getName().c_str());
89     }
90     auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
91     mLayerInfos.emplace_back(layer, std::move(info));
92 }
93 
deregisterLayer(Layer * layer)94 void LayerHistory::deregisterLayer(Layer* layer) {
95     std::lock_guard lock(mLock);
96 
97     const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
98                                  [layer](const auto& pair) { return pair.first == layer; });
99     LOG_ALWAYS_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
100 
101     const size_t i = static_cast<size_t>(it - mLayerInfos.begin());
102     if (i < mActiveLayersEnd) {
103         mActiveLayersEnd--;
104     }
105     const size_t last = mLayerInfos.size() - 1;
106     std::swap(mLayerInfos[i], mLayerInfos[last]);
107     mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(last));
108 }
109 
record(Layer * layer,nsecs_t presentTime,nsecs_t now,LayerUpdateType updateType)110 void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
111                           LayerUpdateType updateType) {
112     std::lock_guard lock(mLock);
113 
114     const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
115                                  [layer](const auto& pair) { return pair.first == layer; });
116     if (it == mLayerInfos.end()) {
117         // Offscreen layer
118         ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str());
119         return;
120     }
121 
122     const auto& info = it->second;
123     const auto layerProps = LayerInfo::LayerProps{
124             .visible = layer->isVisible(),
125             .bounds = layer->getBounds(),
126             .transform = layer->getTransform(),
127             .setFrameRateVote = layer->getFrameRateForLayerTree(),
128             .frameRateSelectionPriority = layer->getFrameRateSelectionPriority(),
129     };
130 
131     info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
132 
133     // Activate layer if inactive.
134     if (const auto end = activeLayers().end(); it >= end) {
135         std::iter_swap(it, end);
136         mActiveLayersEnd++;
137     }
138 }
139 
summarize(const RefreshRateConfigs & refreshRateConfigs,nsecs_t now)140 LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshRateConfigs,
141                                               nsecs_t now) {
142     LayerHistory::Summary summary;
143 
144     std::lock_guard lock(mLock);
145 
146     partitionLayers(now);
147 
148     for (const auto& [layer, info] : activeLayers()) {
149         const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority();
150         const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority);
151         ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
152               layerFocused ? "" : "not");
153 
154         const auto vote = info->getRefreshRateVote(refreshRateConfigs, now);
155         // Skip NoVote layer as those don't have any requirements
156         if (vote.type == LayerHistory::LayerVoteType::NoVote) {
157             continue;
158         }
159 
160         // Compute the layer's position on the screen
161         const Rect bounds = Rect(info->getBounds());
162         const ui::Transform transform = info->getTransform();
163         constexpr bool roundOutwards = true;
164         Rect transformed = transform.transform(bounds, roundOutwards);
165 
166         const float layerArea = transformed.getWidth() * transformed.getHeight();
167         float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f;
168         summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps,
169                            vote.seamlessness, weight, layerFocused});
170 
171         if (CC_UNLIKELY(mTraceEnabled)) {
172             trace(*info, vote.type, vote.fps.getIntValue());
173         }
174     }
175 
176     return summary;
177 }
178 
partitionLayers(nsecs_t now)179 void LayerHistory::partitionLayers(nsecs_t now) {
180     const nsecs_t threshold = getActiveLayerThreshold(now);
181 
182     // Collect expired and inactive layers after active layers.
183     size_t i = 0;
184     while (i < mActiveLayersEnd) {
185         auto& [layerUnsafe, info] = mLayerInfos[i];
186         if (isLayerActive(*info, threshold)) {
187             i++;
188             // Set layer vote if set
189             const auto frameRate = info->getSetFrameRateVote();
190             const auto voteType = [&]() {
191                 switch (frameRate.type) {
192                     case Layer::FrameRateCompatibility::Default:
193                         return LayerVoteType::ExplicitDefault;
194                     case Layer::FrameRateCompatibility::ExactOrMultiple:
195                         return LayerVoteType::ExplicitExactOrMultiple;
196                     case Layer::FrameRateCompatibility::NoVote:
197                         return LayerVoteType::NoVote;
198                     case Layer::FrameRateCompatibility::Exact:
199                         return LayerVoteType::ExplicitExact;
200                 }
201             }();
202 
203             if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) {
204                 const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
205                 info->setLayerVote({type, frameRate.rate, frameRate.seamlessness});
206             } else {
207                 info->resetLayerVote();
208             }
209             continue;
210         }
211 
212         if (CC_UNLIKELY(mTraceEnabled)) {
213             trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
214         }
215 
216         info->onLayerInactive(now);
217         std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
218     }
219 }
220 
clear()221 void LayerHistory::clear() {
222     std::lock_guard lock(mLock);
223 
224     for (const auto& [layer, info] : activeLayers()) {
225         info->clearHistory(systemTime());
226     }
227 }
228 
dump() const229 std::string LayerHistory::dump() const {
230     std::lock_guard lock(mLock);
231     return base::StringPrintf("LayerHistory{size=%zu, active=%zu}", mLayerInfos.size(),
232                               mActiveLayersEnd);
233 }
234 
235 } // namespace android::scheduler
236