1 /*
2 * Copyright (C) 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 #define LOG_TAG "powerhal-libperfmgr"
18
19 #include "Power.h"
20
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <android-base/properties.h>
24 #include <android-base/stringprintf.h>
25 #include <android-base/strings.h>
26 #include <fmq/AidlMessageQueue.h>
27 #include <fmq/EventFlag.h>
28 #include <perfmgr/HintManager.h>
29 #include <utils/Log.h>
30
31 #include <mutex>
32 #include <optional>
33
34 #include "AdpfTypes.h"
35 #include "PowerHintSession.h"
36 #include "PowerSessionManager.h"
37 #include "disp-power/DisplayLowPower.h"
38
39 namespace aidl {
40 namespace google {
41 namespace hardware {
42 namespace power {
43 namespace impl {
44 namespace pixel {
45 using ::android::perfmgr::HintManager;
46
47 constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
48 constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
49 constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
50
Power(std::shared_ptr<DisplayLowPower> dlpw)51 Power::Power(std::shared_ptr<DisplayLowPower> dlpw)
52 : mDisplayLowPower(dlpw),
53 mInteractionHandler(nullptr),
54 mVRModeOn(false),
55 mSustainedPerfModeOn(false) {
56 mInteractionHandler = std::make_unique<InteractionHandler>();
57 mInteractionHandler->Init();
58
59 std::string state = ::android::base::GetProperty(kPowerHalStateProp, "");
60 if (state == "SUSTAINED_PERFORMANCE") {
61 LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE on";
62 HintManager::GetInstance()->DoHint("SUSTAINED_PERFORMANCE");
63 mSustainedPerfModeOn = true;
64 } else if (state == "VR") {
65 LOG(INFO) << "Initialize with VR on";
66 HintManager::GetInstance()->DoHint(state);
67 mVRModeOn = true;
68 } else if (state == "VR_SUSTAINED_PERFORMANCE") {
69 LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE and VR on";
70 HintManager::GetInstance()->DoHint("VR_SUSTAINED_PERFORMANCE");
71 mSustainedPerfModeOn = true;
72 mVRModeOn = true;
73 } else {
74 LOG(INFO) << "Initialize PowerHAL";
75 }
76
77 state = ::android::base::GetProperty(kPowerHalAudioProp, "");
78 if (state == "AUDIO_STREAMING_LOW_LATENCY") {
79 LOG(INFO) << "Initialize with AUDIO_LOW_LATENCY on";
80 HintManager::GetInstance()->DoHint(state);
81 }
82
83 state = ::android::base::GetProperty(kPowerHalRenderingProp, "");
84 if (state == "EXPENSIVE_RENDERING") {
85 LOG(INFO) << "Initialize with EXPENSIVE_RENDERING on";
86 HintManager::GetInstance()->DoHint("EXPENSIVE_RENDERING");
87 }
88
89 auto status = this->getInterfaceVersion(&mServiceVersion);
90 LOG(INFO) << "PowerHAL InterfaceVersion:" << mServiceVersion << " isOK: " << status.isOk();
91 }
92
setMode(Mode type,bool enabled)93 ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
94 LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled;
95 if (HintManager::GetInstance()->GetAdpfProfile() &&
96 HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs > 0) {
97 PowerSessionManager<>::getInstance()->updateHintMode(toString(type), enabled);
98 }
99 switch (type) {
100 case Mode::LOW_POWER:
101 mDisplayLowPower->SetDisplayLowPower(enabled);
102 if (enabled) {
103 HintManager::GetInstance()->DoHint(toString(type));
104 } else {
105 HintManager::GetInstance()->EndHint(toString(type));
106 }
107 break;
108 case Mode::SUSTAINED_PERFORMANCE:
109 if (enabled && !mSustainedPerfModeOn) {
110 if (!mVRModeOn) { // Sustained mode only.
111 HintManager::GetInstance()->DoHint("SUSTAINED_PERFORMANCE");
112 } else { // Sustained + VR mode.
113 HintManager::GetInstance()->EndHint("VR");
114 HintManager::GetInstance()->DoHint("VR_SUSTAINED_PERFORMANCE");
115 }
116 mSustainedPerfModeOn = true;
117 } else if (!enabled && mSustainedPerfModeOn) {
118 HintManager::GetInstance()->EndHint("VR_SUSTAINED_PERFORMANCE");
119 HintManager::GetInstance()->EndHint("SUSTAINED_PERFORMANCE");
120 if (mVRModeOn) { // Switch back to VR Mode.
121 HintManager::GetInstance()->DoHint("VR");
122 }
123 mSustainedPerfModeOn = false;
124 }
125 break;
126 case Mode::VR:
127 if (enabled && !mVRModeOn) {
128 if (!mSustainedPerfModeOn) { // VR mode only.
129 HintManager::GetInstance()->DoHint("VR");
130 } else { // Sustained + VR mode.
131 HintManager::GetInstance()->EndHint("SUSTAINED_PERFORMANCE");
132 HintManager::GetInstance()->DoHint("VR_SUSTAINED_PERFORMANCE");
133 }
134 mVRModeOn = true;
135 } else if (!enabled && mVRModeOn) {
136 HintManager::GetInstance()->EndHint("VR_SUSTAINED_PERFORMANCE");
137 HintManager::GetInstance()->EndHint("VR");
138 if (mSustainedPerfModeOn) { // Switch back to sustained Mode.
139 HintManager::GetInstance()->DoHint("SUSTAINED_PERFORMANCE");
140 }
141 mVRModeOn = false;
142 }
143 break;
144 case Mode::LAUNCH:
145 if (mVRModeOn || mSustainedPerfModeOn) {
146 break;
147 }
148 [[fallthrough]];
149 case Mode::DOUBLE_TAP_TO_WAKE:
150 [[fallthrough]];
151 case Mode::FIXED_PERFORMANCE:
152 [[fallthrough]];
153 case Mode::EXPENSIVE_RENDERING:
154 [[fallthrough]];
155 case Mode::INTERACTIVE:
156 [[fallthrough]];
157 case Mode::DEVICE_IDLE:
158 [[fallthrough]];
159 case Mode::DISPLAY_INACTIVE:
160 [[fallthrough]];
161 case Mode::AUDIO_STREAMING_LOW_LATENCY:
162 [[fallthrough]];
163 case Mode::CAMERA_STREAMING_SECURE:
164 [[fallthrough]];
165 case Mode::CAMERA_STREAMING_LOW:
166 [[fallthrough]];
167 case Mode::CAMERA_STREAMING_MID:
168 [[fallthrough]];
169 case Mode::CAMERA_STREAMING_HIGH:
170 [[fallthrough]];
171 case Mode::GAME_LOADING:
172 [[fallthrough]];
173 default:
174 if (enabled) {
175 HintManager::GetInstance()->DoHint(toString(type));
176 } else {
177 HintManager::GetInstance()->EndHint(toString(type));
178 }
179 break;
180 }
181
182 return ndk::ScopedAStatus::ok();
183 }
184
isModeSupported(Mode type,bool * _aidl_return)185 ndk::ScopedAStatus Power::isModeSupported(Mode type, bool *_aidl_return) {
186 switch (mServiceVersion) {
187 case 5:
188 if (static_cast<int32_t>(type) <= static_cast<int32_t>(Mode::AUTOMOTIVE_PROJECTION))
189 break;
190 [[fallthrough]];
191 case 4:
192 [[fallthrough]];
193 case 3:
194 if (static_cast<int32_t>(type) <= static_cast<int32_t>(Mode::GAME_LOADING))
195 break;
196 [[fallthrough]];
197 case 2:
198 [[fallthrough]];
199 case 1:
200 if (static_cast<int32_t>(type) <= static_cast<int32_t>(Mode::CAMERA_STREAMING_HIGH))
201 break;
202 [[fallthrough]];
203 default:
204 *_aidl_return = false;
205 return ndk::ScopedAStatus::ok();
206 }
207 bool supported = HintManager::GetInstance()->IsHintSupported(toString(type));
208 // LOW_POWER handled insides PowerHAL specifically
209 if (type == Mode::LOW_POWER) {
210 supported = true;
211 }
212 if (!supported && HintManager::GetInstance()->IsAdpfProfileSupported(toString(type))) {
213 supported = true;
214 }
215 LOG(INFO) << "Power mode " << toString(type) << " isModeSupported: " << supported;
216 *_aidl_return = supported;
217 return ndk::ScopedAStatus::ok();
218 }
219
setBoost(Boost type,int32_t durationMs)220 ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
221 LOG(DEBUG) << "Power setBoost: " << toString(type) << " duration: " << durationMs;
222 if (HintManager::GetInstance()->GetAdpfProfile() &&
223 HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs > 0) {
224 PowerSessionManager<>::getInstance()->updateHintBoost(toString(type), durationMs);
225 }
226 switch (type) {
227 case Boost::INTERACTION:
228 if (mVRModeOn || mSustainedPerfModeOn) {
229 break;
230 }
231 mInteractionHandler->Acquire(durationMs);
232 break;
233 case Boost::DISPLAY_UPDATE_IMMINENT:
234 [[fallthrough]];
235 case Boost::ML_ACC:
236 [[fallthrough]];
237 case Boost::AUDIO_LAUNCH:
238 [[fallthrough]];
239 case Boost::CAMERA_LAUNCH:
240 [[fallthrough]];
241 case Boost::CAMERA_SHOT:
242 [[fallthrough]];
243 default:
244 if (mVRModeOn || mSustainedPerfModeOn) {
245 break;
246 }
247 if (durationMs > 0) {
248 HintManager::GetInstance()->DoHint(toString(type),
249 std::chrono::milliseconds(durationMs));
250 } else if (durationMs == 0) {
251 HintManager::GetInstance()->DoHint(toString(type));
252 } else {
253 HintManager::GetInstance()->EndHint(toString(type));
254 }
255 break;
256 }
257
258 return ndk::ScopedAStatus::ok();
259 }
260
isBoostSupported(Boost type,bool * _aidl_return)261 ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool *_aidl_return) {
262 switch (mServiceVersion) {
263 case 5:
264 [[fallthrough]];
265 case 4:
266 [[fallthrough]];
267 case 3:
268 [[fallthrough]];
269 case 2:
270 [[fallthrough]];
271 case 1:
272 if (static_cast<int32_t>(type) <= static_cast<int32_t>(Boost::CAMERA_SHOT))
273 break;
274 [[fallthrough]];
275 default:
276 *_aidl_return = false;
277 return ndk::ScopedAStatus::ok();
278 }
279 bool supported = HintManager::GetInstance()->IsHintSupported(toString(type));
280 if (!supported && HintManager::GetInstance()->IsAdpfProfileSupported(toString(type))) {
281 supported = true;
282 }
283 LOG(INFO) << "Power boost " << toString(type) << " isBoostSupported: " << supported;
284 *_aidl_return = supported;
285 return ndk::ScopedAStatus::ok();
286 }
287
boolToString(bool b)288 constexpr const char *boolToString(bool b) {
289 return b ? "true" : "false";
290 }
291
dump(int fd,const char **,uint32_t)292 binder_status_t Power::dump(int fd, const char **, uint32_t) {
293 std::string buf(::android::base::StringPrintf(
294 "HintManager Running: %s\n"
295 "VRMode: %s\n"
296 "SustainedPerformanceMode: %s\n",
297 boolToString(HintManager::GetInstance()->IsRunning()), boolToString(mVRModeOn),
298 boolToString(mSustainedPerfModeOn)));
299 // Dump nodes through libperfmgr
300 HintManager::GetInstance()->DumpToFd(fd);
301 PowerSessionManager<>::getInstance()->dumpToFd(fd);
302 if (!::android::base::WriteStringToFd(buf, fd)) {
303 PLOG(ERROR) << "Failed to dump state to fd";
304 }
305 fsync(fd);
306 return STATUS_OK;
307 }
308
createHintSession(int32_t tgid,int32_t uid,const std::vector<int32_t> & threadIds,int64_t durationNanos,std::shared_ptr<IPowerHintSession> * _aidl_return)309 ndk::ScopedAStatus Power::createHintSession(int32_t tgid, int32_t uid,
310 const std::vector<int32_t> &threadIds,
311 int64_t durationNanos,
312 std::shared_ptr<IPowerHintSession> *_aidl_return) {
313 SessionConfig config;
314 return createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, SessionTag::OTHER,
315 &config, _aidl_return);
316 }
317
getHintSessionPreferredRate(int64_t * outNanoseconds)318 ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t *outNanoseconds) {
319 *outNanoseconds = HintManager::GetInstance()->GetAdpfProfile()
320 ? HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs
321 : 0;
322 if (*outNanoseconds <= 0) {
323 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
324 }
325
326 return ndk::ScopedAStatus::ok();
327 }
328
createHintSessionWithConfig(int32_t tgid,int32_t uid,const std::vector<int32_t> & threadIds,int64_t durationNanos,SessionTag tag,SessionConfig * config,std::shared_ptr<IPowerHintSession> * _aidl_return)329 ndk::ScopedAStatus Power::createHintSessionWithConfig(
330 int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds, int64_t durationNanos,
331 SessionTag tag, SessionConfig *config, std::shared_ptr<IPowerHintSession> *_aidl_return) {
332 if (!HintManager::GetInstance()->GetAdpfProfile() ||
333 HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs <= 0) {
334 *_aidl_return = nullptr;
335 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
336 }
337 if (threadIds.size() == 0) {
338 LOG(ERROR) << "Error: threadIds.size() shouldn't be " << threadIds.size();
339 *_aidl_return = nullptr;
340 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
341 }
342 std::shared_ptr<PowerHintSession<>> session =
343 ndk::SharedRefBase::make<PowerHintSession<>>(tgid, uid, threadIds, durationNanos, tag);
344
345 *_aidl_return = session;
346 session->getSessionConfig(config);
347 PowerSessionManager<>::getInstance()->registerSession(session, config->id);
348
349 return ndk::ScopedAStatus::ok();
350 }
351
getSessionChannel(int32_t,int32_t,ChannelConfig * _aidl_return)352 ndk::ScopedAStatus Power::getSessionChannel(int32_t, int32_t, ChannelConfig *_aidl_return) {
353 static AidlMessageQueue<ChannelMessage, SynchronizedReadWrite> stubQueue{20, true};
354 static std::thread stubThread([&] {
355 ChannelMessage data;
356 // This loop will only run while there is data waiting
357 // to be processed, and blocks on a futex all other times
358 while (stubQueue.readBlocking(&data, 1, 0)) {
359 }
360 });
361 _aidl_return->channelDescriptor = stubQueue.dupeDesc();
362 _aidl_return->readFlagBitmask = 0x01;
363 _aidl_return->writeFlagBitmask = 0x02;
364 _aidl_return->eventFlagDescriptor = std::nullopt;
365 return ndk::ScopedAStatus::ok();
366 }
367
closeSessionChannel(int32_t,int32_t)368 ndk::ScopedAStatus Power::closeSessionChannel(int32_t, int32_t) {
369 return ndk::ScopedAStatus::ok();
370 }
371
372 } // namespace pixel
373 } // namespace impl
374 } // namespace power
375 } // namespace hardware
376 } // namespace google
377 } // namespace aidl
378