1 /*
2 * Copyright 2018 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 //#define LOG_NDEBUG 0
18
19 #undef LOG_TAG
20 #define LOG_TAG "PowerAdvisor"
21
22 #include <cinttypes>
23
24 #include <android-base/properties.h>
25 #include <utils/Log.h>
26 #include <utils/Mutex.h>
27
28 #include <android/hardware/power/1.3/IPower.h>
29 #include <android/hardware/power/IPower.h>
30 #include <binder/IServiceManager.h>
31
32 #include "../SurfaceFlingerProperties.h"
33
34 #include "PowerAdvisor.h"
35 #include "SurfaceFlinger.h"
36
37 namespace android {
38 namespace Hwc2 {
39
40 PowerAdvisor::~PowerAdvisor() = default;
41
42 namespace impl {
43
44 namespace V1_0 = android::hardware::power::V1_0;
45 namespace V1_3 = android::hardware::power::V1_3;
46 using V1_3::PowerHint;
47
48 using android::hardware::power::Boost;
49 using android::hardware::power::IPower;
50 using android::hardware::power::Mode;
51 using base::GetIntProperty;
52 using scheduler::OneShotTimer;
53
54 PowerAdvisor::~PowerAdvisor() = default;
55
56 namespace {
getUpdateTimeout()57 int32_t getUpdateTimeout() {
58 // Default to a timeout of 80ms if nothing else is specified
59 static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80);
60 return timeout;
61 }
62
63 } // namespace
64
PowerAdvisor(SurfaceFlinger & flinger)65 PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger)
66 : mFlinger(flinger),
67 mUseScreenUpdateTimer(getUpdateTimeout() > 0),
68 mScreenUpdateTimer(
69 "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
70 /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
71 /* timeoutCallback */
__anonb6262e2c0302null72 [this] {
73 mSendUpdateImminent.store(true);
74 mFlinger.disableExpensiveRendering();
75 }) {}
76
init()77 void PowerAdvisor::init() {
78 // Defer starting the screen update timer until SurfaceFlinger finishes construction.
79 if (mUseScreenUpdateTimer) {
80 mScreenUpdateTimer.start();
81 }
82 }
83
onBootFinished()84 void PowerAdvisor::onBootFinished() {
85 mBootFinished.store(true);
86 }
87
setExpensiveRenderingExpected(DisplayId displayId,bool expected)88 void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
89 if (expected) {
90 mExpensiveDisplays.insert(displayId);
91 } else {
92 mExpensiveDisplays.erase(displayId);
93 }
94
95 const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
96 if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
97 std::lock_guard lock(mPowerHalMutex);
98 HalWrapper* const halWrapper = getPowerHal();
99 if (halWrapper == nullptr) {
100 return;
101 }
102
103 if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) {
104 // The HAL has become unavailable; attempt to reconnect later
105 mReconnectPowerHal = true;
106 return;
107 }
108
109 mNotifiedExpensiveRendering = expectsExpensiveRendering;
110 }
111 }
112
notifyDisplayUpdateImminent()113 void PowerAdvisor::notifyDisplayUpdateImminent() {
114 // Only start sending this notification once the system has booted so we don't introduce an
115 // early-boot dependency on Power HAL
116 if (!mBootFinished.load()) {
117 return;
118 }
119
120 if (mSendUpdateImminent.load()) {
121 std::lock_guard lock(mPowerHalMutex);
122 HalWrapper* const halWrapper = getPowerHal();
123 if (halWrapper == nullptr) {
124 return;
125 }
126
127 if (!halWrapper->notifyDisplayUpdateImminent()) {
128 // The HAL has become unavailable; attempt to reconnect later
129 mReconnectPowerHal = true;
130 return;
131 }
132 }
133
134 if (mUseScreenUpdateTimer) {
135 mScreenUpdateTimer.reset();
136 }
137 }
138
139 class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
140 public:
HidlPowerHalWrapper(sp<V1_3::IPower> powerHal)141 HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
142
143 ~HidlPowerHalWrapper() override = default;
144
connect()145 static std::unique_ptr<HalWrapper> connect() {
146 // Power HAL 1.3 is not guaranteed to be available, thus we need to query
147 // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
148 sp<V1_3::IPower> powerHal = nullptr;
149 sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
150 if (powerHal_1_0 != nullptr) {
151 // Try to cast to Power HAL 1.3
152 powerHal = V1_3::IPower::castFrom(powerHal_1_0);
153 if (powerHal == nullptr) {
154 ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor");
155 } else {
156 ALOGI("Loaded Power HAL 1.3 service");
157 }
158 } else {
159 ALOGW("No Power HAL found, disabling PowerAdvisor");
160 }
161
162 if (powerHal == nullptr) {
163 return nullptr;
164 }
165
166 return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal));
167 }
168
setExpensiveRendering(bool enabled)169 bool setExpensiveRendering(bool enabled) override {
170 ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
171 auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
172 return ret.isOk();
173 }
174
notifyDisplayUpdateImminent()175 bool notifyDisplayUpdateImminent() override {
176 // Power HAL 1.x doesn't have a notification for this
177 ALOGV("HIDL notifyUpdateImminent received but can't send");
178 return true;
179 }
180
181 private:
182 const sp<V1_3::IPower> mPowerHal = nullptr;
183 };
184
185 class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
186 public:
AidlPowerHalWrapper(sp<IPower> powerHal)187 AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
188 auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
189 if (!ret.isOk()) {
190 mHasExpensiveRendering = false;
191 }
192
193 ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
194 &mHasDisplayUpdateImminent);
195 if (!ret.isOk()) {
196 mHasDisplayUpdateImminent = false;
197 }
198 }
199
200 ~AidlPowerHalWrapper() override = default;
201
connect()202 static std::unique_ptr<HalWrapper> connect() {
203 // This only waits if the service is actually declared
204 sp<IPower> powerHal = waitForVintfService<IPower>();
205 if (powerHal == nullptr) {
206 return nullptr;
207 }
208 ALOGI("Loaded AIDL Power HAL service");
209
210 return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
211 }
212
setExpensiveRendering(bool enabled)213 bool setExpensiveRendering(bool enabled) override {
214 ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
215 if (!mHasExpensiveRendering) {
216 ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
217 return true;
218 }
219
220 auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
221 return ret.isOk();
222 }
223
notifyDisplayUpdateImminent()224 bool notifyDisplayUpdateImminent() override {
225 ALOGV("AIDL notifyDisplayUpdateImminent");
226 if (!mHasDisplayUpdateImminent) {
227 ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
228 return true;
229 }
230
231 auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
232 return ret.isOk();
233 }
234
235 private:
236 const sp<IPower> mPowerHal = nullptr;
237 bool mHasExpensiveRendering = false;
238 bool mHasDisplayUpdateImminent = false;
239 };
240
getPowerHal()241 PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
242 static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
243 static bool sHasHal = true;
244
245 if (!sHasHal) {
246 return nullptr;
247 }
248
249 // If we used to have a HAL, but it stopped responding, attempt to reconnect
250 if (mReconnectPowerHal) {
251 sHalWrapper = nullptr;
252 mReconnectPowerHal = false;
253 }
254
255 if (sHalWrapper != nullptr) {
256 return sHalWrapper.get();
257 }
258
259 // First attempt to connect to the AIDL Power HAL
260 sHalWrapper = AidlPowerHalWrapper::connect();
261
262 // If that didn't succeed, attempt to connect to the HIDL Power HAL
263 if (sHalWrapper == nullptr) {
264 sHalWrapper = HidlPowerHalWrapper::connect();
265 }
266
267 // If we make it to this point and still don't have a HAL, it's unlikely we
268 // will, so stop trying
269 if (sHalWrapper == nullptr) {
270 sHasHal = false;
271 }
272
273 return sHalWrapper.get();
274 }
275
276 } // namespace impl
277 } // namespace Hwc2
278 } // namespace android
279