1 /*
2  * Copyright (C) 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 ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
18 #define LOG_TAG "android.hardware.power@1.3-service.pixel-libperfmgr"
19 
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25 
26 #include <mutex>
27 
28 #include <utils/Log.h>
29 #include <utils/Trace.h>
30 
31 #include "AudioStreaming.h"
32 #include "Power.h"
33 #include "display-helper.h"
34 
35 namespace android {
36 namespace hardware {
37 namespace power {
38 namespace V1_3 {
39 namespace implementation {
40 
41 using ::android::hardware::hidl_vec;
42 using ::android::hardware::Return;
43 using ::android::hardware::Void;
44 using ::android::hardware::power::V1_0::Feature;
45 using ::android::hardware::power::V1_0::Status;
46 
47 constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
48 constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
49 constexpr char kPowerHalInitProp[] = "vendor.powerhal.init";
50 constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
51 constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json";
52 
53 static const std::map<enum CameraStreamingMode, std::string> kCamStreamingHint = {
54         {CAMERA_STREAMING_OFF, "CAMERA_STREAMING_OFF"},
55         {CAMERA_STREAMING, "CAMERA_STREAMING"},
56         {CAMERA_STREAMING_1080P, "CAMERA_STREAMING_1080P"},
57         {CAMERA_STREAMING_60FPS, "CAMERA_STREAMING_60FPS"},
58         {CAMERA_STREAMING_4K, "CAMERA_STREAMING_4K"},
59         {CAMERA_STREAMING_SECURE, "CAMERA_STREAMING_SECURE"}};
60 
Power()61 Power::Power()
62     : mHintManager(nullptr),
63       mInteractionHandler(nullptr),
64       mVRModeOn(false),
65       mSustainedPerfModeOn(false),
66       mCameraStreamingMode(CAMERA_STREAMING_OFF),
67       mReady(false) {
68     mInitThread = std::thread([this]() {
69         android::base::WaitForProperty(kPowerHalInitProp, "1");
70         mHintManager = HintManager::GetFromJSON(kPowerHalConfigPath);
71         if (!mHintManager) {
72             LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath;
73         }
74         mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager);
75         mInteractionHandler->Init();
76         std::string state = android::base::GetProperty(kPowerHalStateProp, "");
77         if (state == "CAMERA_STREAMING") {
78             ALOGI("Initialize with CAMERA_STREAMING on");
79             mHintManager->DoHint("CAMERA_STREAMING");
80             mCameraStreamingMode = CAMERA_STREAMING;
81         } else if (state == "CAMERA_STREAMING_1080P") {
82             ALOGI("Initialize CAMERA_STREAMING_1080P on");
83             mHintManager->DoHint("CAMERA_STREAMING_1080P");
84             mCameraStreamingMode = CAMERA_STREAMING_1080P;
85         } else if (state == "CAMERA_STREAMING_60FPS") {
86             ALOGI("Initialize CAMERA_STREAMING_60FPS on");
87             mHintManager->DoHint("CAMERA_STREAMING_60FPS");
88             mCameraStreamingMode = CAMERA_STREAMING_60FPS;
89         } else if (state == "CAMERA_STREAMING_4K") {
90             ALOGI("Initialize with CAMERA_STREAMING_4K on");
91             mHintManager->DoHint("CAMERA_STREAMING_4K");
92             mCameraStreamingMode = CAMERA_STREAMING_4K;
93         } else if (state == "CAMERA_STREAMING_SECURE") {
94             ALOGI("Initialize with CAMERA_STREAMING_SECURE on");
95             mHintManager->DoHint("CAMERA_STREAMING_SECURE");
96             mCameraStreamingMode = CAMERA_STREAMING_SECURE;
97         } else if (state == "SUSTAINED_PERFORMANCE") {
98             ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
99             mHintManager->DoHint("SUSTAINED_PERFORMANCE");
100             mSustainedPerfModeOn = true;
101         } else if (state == "VR_MODE") {
102             ALOGI("Initialize with VR_MODE on");
103             mHintManager->DoHint("VR_MODE");
104             mVRModeOn = true;
105         } else if (state == "VR_SUSTAINED_PERFORMANCE") {
106             ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR_MODE on");
107             mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
108             mSustainedPerfModeOn = true;
109             mVRModeOn = true;
110         } else {
111             ALOGI("Initialize PowerHAL");
112         }
113 
114         state = android::base::GetProperty(kPowerHalAudioProp, "");
115         if (state == "AUDIO_LOW_LATENCY") {
116             ALOGI("Initialize with AUDIO_LOW_LATENCY on");
117             mHintManager->DoHint("AUDIO_LOW_LATENCY");
118         }
119 
120         state = android::base::GetProperty(kPowerHalRenderingProp, "");
121         if (state == "EXPENSIVE_RENDERING") {
122             ALOGI("Initialize with EXPENSIVE_RENDERING on");
123             mHintManager->DoHint("EXPENSIVE_RENDERING");
124         }
125         // Now start to take powerhint
126         mReady.store(true);
127         ALOGI("PowerHAL ready to process hints");
128     });
129     mInitThread.detach();
130 }
131 
132 // Methods from ::android::hardware::power::V1_0::IPower follow.
setInteractive(bool)133 Return<void> Power::setInteractive(bool /* interactive */) {
134     return Void();
135 }
136 
powerHint(PowerHint_1_0 hint,int32_t data)137 Return<void> Power::powerHint(PowerHint_1_0 hint, int32_t data) {
138     if (!mReady) {
139         return Void();
140     }
141     ATRACE_INT(android::hardware::power::V1_0::toString(hint).c_str(), data);
142     ALOGD_IF(hint != PowerHint_1_0::INTERACTION, "%s: %d",
143              android::hardware::power::V1_0::toString(hint).c_str(), static_cast<int>(data));
144     switch (hint) {
145         case PowerHint_1_0::INTERACTION:
146             if (mVRModeOn || mSustainedPerfModeOn) {
147                 ALOGV("%s: ignoring due to other active perf hints", __func__);
148             } else {
149                 mInteractionHandler->Acquire(data);
150             }
151             break;
152         case PowerHint_1_0::SUSTAINED_PERFORMANCE:
153             if (data && !mSustainedPerfModeOn) {
154                 if (!mVRModeOn) {  // Sustained mode only.
155                     mHintManager->DoHint("SUSTAINED_PERFORMANCE");
156                 } else {  // Sustained + VR mode.
157                     mHintManager->EndHint("VR_MODE");
158                     mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
159                 }
160                 mSustainedPerfModeOn = true;
161             } else if (!data && mSustainedPerfModeOn) {
162                 mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
163                 mHintManager->EndHint("SUSTAINED_PERFORMANCE");
164                 if (mVRModeOn) {  // Switch back to VR Mode.
165                     mHintManager->DoHint("VR_MODE");
166                 }
167                 mSustainedPerfModeOn = false;
168             }
169             break;
170         case PowerHint_1_0::VR_MODE:
171             if (data && !mVRModeOn) {
172                 if (!mSustainedPerfModeOn) {  // VR mode only.
173                     mHintManager->DoHint("VR_MODE");
174                 } else {  // Sustained + VR mode.
175                     mHintManager->EndHint("SUSTAINED_PERFORMANCE");
176                     mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
177                 }
178                 mVRModeOn = true;
179             } else if (!data && mVRModeOn) {
180                 mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
181                 mHintManager->EndHint("VR_MODE");
182                 if (mSustainedPerfModeOn) {  // Switch back to sustained Mode.
183                     mHintManager->DoHint("SUSTAINED_PERFORMANCE");
184                 }
185                 mVRModeOn = false;
186             }
187             break;
188         case PowerHint_1_0::LAUNCH:
189             if (mVRModeOn || mSustainedPerfModeOn) {
190                 ALOGV("%s: ignoring due to other active perf hints", __func__);
191             } else {
192                 if (data) {
193                     // Hint until canceled
194                     mHintManager->DoHint("LAUNCH");
195                 } else {
196                     mHintManager->EndHint("LAUNCH");
197                 }
198             }
199             break;
200         case PowerHint_1_0::LOW_POWER:
201             if (data) {
202                 // Device in battery saver mode, enable display low power mode
203                 set_display_lpm(true);
204             } else {
205                 // Device exiting battery saver mode, disable display low power mode
206                 set_display_lpm(false);
207             }
208             break;
209         default:
210             break;
211     }
212     return Void();
213 }
214 
setFeature(Feature,bool)215 Return<void> Power::setFeature(Feature /*feature*/, bool /*activate*/) {
216     // Nothing to do
217     return Void();
218 }
219 
getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb)220 Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
221     LOG(ERROR) << "getPlatformLowPowerStats not supported. Use IPowerStats HAL.";
222     _hidl_cb({}, Status::SUCCESS);
223     return Void();
224 }
225 
226 // Methods from ::android::hardware::power::V1_1::IPower follow.
getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb)227 Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
228     LOG(ERROR) << "getSubsystemLowPowerStats not supported. Use IPowerStats HAL.";
229     _hidl_cb({}, Status::SUCCESS);
230     return Void();
231 }
232 
powerHintAsync(PowerHint_1_0 hint,int32_t data)233 Return<void> Power::powerHintAsync(PowerHint_1_0 hint, int32_t data) {
234     // just call the normal power hint in this oneway function
235     return powerHint(hint, data);
236 }
237 
238 // Methods from ::android::hardware::power::V1_2::IPower follow.
powerHintAsync_1_2(PowerHint_1_2 hint,int32_t data)239 Return<void> Power::powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) {
240     if (!mReady) {
241         return Void();
242     }
243 
244     ATRACE_INT(android::hardware::power::V1_2::toString(hint).c_str(), data);
245     ALOGD_IF(hint >= PowerHint_1_2::AUDIO_STREAMING, "%s: %d",
246              android::hardware::power::V1_2::toString(hint).c_str(), static_cast<int>(data));
247 
248     switch (hint) {
249         case PowerHint_1_2::AUDIO_LOW_LATENCY:
250             if (data) {
251                 // Hint until canceled
252                 mHintManager->DoHint("AUDIO_LOW_LATENCY");
253             } else {
254                 mHintManager->EndHint("AUDIO_LOW_LATENCY");
255             }
256             break;
257         case PowerHint_1_2::AUDIO_STREAMING:
258             if (mVRModeOn || mSustainedPerfModeOn) {
259                 ALOGV("%s: ignoring due to other active perf hints", __func__);
260             } else {
261                 if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::AUDIO_STREAMING_ON)) {
262                     mHintManager->DoHint("AUDIO_STREAMING");
263                 } else if (data ==
264                            static_cast<int32_t>(AUDIO_STREAMING_HINT::AUDIO_STREAMING_OFF)) {
265                     mHintManager->EndHint("AUDIO_STREAMING");
266                 } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_SHORT)) {
267                     mHintManager->DoHint("TPU_BOOST",
268                                          std::chrono::milliseconds(TPU_HINT_DURATION_MS::SHORT));
269                 } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_LONG)) {
270                     mHintManager->DoHint("TPU_BOOST",
271                                          std::chrono::milliseconds(TPU_HINT_DURATION_MS::LONG));
272                 } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_OFF)) {
273                     mHintManager->EndHint("TPU_BOOST");
274                 } else {
275                     ALOGE("AUDIO STREAMING INVALID DATA: %d", data);
276                 }
277             }
278             break;
279         case PowerHint_1_2::CAMERA_LAUNCH:
280             if (data > 0) {
281                 mHintManager->DoHint("CAMERA_LAUNCH");
282             } else if (data == 0) {
283                 mHintManager->EndHint("CAMERA_LAUNCH");
284             } else {
285                 ALOGE("CAMERA LAUNCH INVALID DATA: %d", data);
286             }
287             break;
288         case PowerHint_1_2::CAMERA_STREAMING: {
289             const enum CameraStreamingMode mode = static_cast<enum CameraStreamingMode>(data);
290             if (mode < CAMERA_STREAMING_OFF || mode >= CAMERA_STREAMING_MAX) {
291                 ALOGE("CAMERA STREAMING INVALID Mode: %d", mode);
292                 break;
293             }
294 
295             if (mCameraStreamingMode == mode)
296                 break;
297 
298             // turn it off first if any previous hint.
299             if ((mCameraStreamingMode != CAMERA_STREAMING_OFF)) {
300                 const auto modeValue = kCamStreamingHint.at(mCameraStreamingMode);
301                 mHintManager->EndHint(modeValue);
302                 if ((mCameraStreamingMode != CAMERA_STREAMING_SECURE)) {
303                     // Boost 1s for tear down if not secure streaming use case
304                     mHintManager->DoHint("CAMERA_LAUNCH", std::chrono::seconds(1));
305                 }
306             }
307 
308             if (mode != CAMERA_STREAMING_OFF) {
309                 const auto hintValue = kCamStreamingHint.at(mode);
310                 mHintManager->DoHint(hintValue);
311             }
312 
313             mCameraStreamingMode = mode;
314             const auto prop = (mCameraStreamingMode == CAMERA_STREAMING_OFF)
315                                   ? ""
316                                   : kCamStreamingHint.at(mode).c_str();
317             if (!android::base::SetProperty(kPowerHalStateProp, prop)) {
318                 ALOGE("%s: could set powerHAL state %s property", __func__, prop);
319             }
320             break;
321         }
322         case PowerHint_1_2::CAMERA_SHOT:
323             if (data > 0) {
324                 mHintManager->DoHint("CAMERA_SHOT", std::chrono::milliseconds(data));
325             } else if (data == 0) {
326                 mHintManager->EndHint("CAMERA_SHOT");
327             } else {
328                 ALOGE("CAMERA SHOT INVALID DATA: %d", data);
329             }
330             break;
331         default:
332             return powerHint(static_cast<PowerHint_1_0>(hint), data);
333     }
334     return Void();
335 }
336 
337 // Methods from ::android::hardware::power::V1_3::IPower follow.
powerHintAsync_1_3(PowerHint_1_3 hint,int32_t data)338 Return<void> Power::powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) {
339     if (!mReady) {
340         return Void();
341     }
342 
343     if (hint == PowerHint_1_3::EXPENSIVE_RENDERING) {
344         ATRACE_INT(android::hardware::power::V1_3::toString(hint).c_str(), data);
345         if (mVRModeOn || mSustainedPerfModeOn) {
346             ALOGV("%s: ignoring due to other active perf hints", __func__);
347         } else {
348             if (data > 0) {
349                 mHintManager->DoHint("EXPENSIVE_RENDERING");
350             } else {
351                 mHintManager->EndHint("EXPENSIVE_RENDERING");
352             }
353         }
354     } else {
355         return powerHintAsync_1_2(static_cast<PowerHint_1_2>(hint), data);
356     }
357     return Void();
358 }
359 
boolToString(bool b)360 constexpr const char *boolToString(bool b) {
361     return b ? "true" : "false";
362 }
363 
debug(const hidl_handle & handle,const hidl_vec<hidl_string> &)364 Return<void> Power::debug(const hidl_handle &handle, const hidl_vec<hidl_string> &) {
365     if (handle != nullptr && handle->numFds >= 1 && mReady) {
366         int fd = handle->data[0];
367 
368         std::string buf(android::base::StringPrintf(
369             "HintManager Running: %s\n"
370             "VRMode: %s\n"
371             "CameraStreamingMode: %s\n"
372             "SustainedPerformanceMode: %s\n",
373             boolToString(mHintManager->IsRunning()), boolToString(mVRModeOn),
374             kCamStreamingHint.at(mCameraStreamingMode).c_str(),
375             boolToString(mSustainedPerfModeOn)));
376         // Dump nodes through libperfmgr
377         mHintManager->DumpToFd(fd);
378         if (!android::base::WriteStringToFd(buf, fd)) {
379             PLOG(ERROR) << "Failed to dump state to fd";
380         }
381         fsync(fd);
382     }
383     return Void();
384 }
385 
386 }  // namespace implementation
387 }  // namespace V1_3
388 }  // namespace power
389 }  // namespace hardware
390 }  // namespace android
391