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