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