--- /dev/null
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+ name: "pixel_power_headers",
+ vendor_available: true,
+ export_include_dirs: ["."],
+}
+
+cc_binary {
+ name: "android.hardware.power@1.3-service.pixel-libperfmgr",
+ relative_install_path: "hw",
+ vintf_fragments: ["android.hardware.power@1.3-service.pixel.xml"],
+ init_rc: ["android.hardware.power@1.3-service.pixel-libperfmgr.rc"],
+ srcs: ["service.cpp", "Power.cpp", "InteractionHandler.cpp",
+ "display-helper.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
+ "android.hardware.power@1.2",
+ "android.hardware.power@1.3",
+ "libperfmgr",
+ ],
+ proprietary: true,
+}
--- /dev/null
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef POWER_LIBPERFMGR_AUDIOSTREAMING_H_
+#define POWER_LIBPERFMGR_AUDIOSTREAMING_H_
+
+enum AUDIO_STREAMING_HINT {
+ AUDIO_STREAMING_OFF = 0,
+ AUDIO_STREAMING_ON = 1,
+ TPU_BOOST_OFF = 1000,
+ TPU_BOOST_SHORT = 1001,
+ TPU_BOOST_LONG = 1002
+};
+
+enum TPU_HINT_DURATION_MS { SHORT = 200, LONG = 2000 };
+
+#endif // POWER_LIBPERFMGR_AUDIOSTREAMING_H_
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef POWER_LIBPERFMGR_CAMERAMODE_H_
+#define POWER_LIBPERFMGR_CAMERAMODE_H_
+
+enum CameraStreamingMode {
+ CAMERA_STREAMING_OFF = 0,
+ CAMERA_STREAMING,
+ CAMERA_STREAMING_1080P,
+ CAMERA_STREAMING_60FPS,
+ CAMERA_STREAMING_4K,
+ CAMERA_STREAMING_SECURE,
+ CAMERA_STREAMING_MAX
+};
+
+#endif // POWER_LIBPERFMGR_CAMERAMODE_H_
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.power@1.3-service.pixel-libperfmgr"
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/eventfd.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <memory>
+
+#include "InteractionHandler.h"
+
+#define MAX_LENGTH 64
+
+#define MSINSEC 1000L
+#define USINMS 1000000L
+
+static const std::vector<std::string> fb_idle_patch = {"/sys/class/drm/card0/device/idle_state",
+ "/sys/class/graphics/fb0/idle_state"};
+
+InteractionHandler::InteractionHandler(std::shared_ptr<HintManager> const &hint_manager)
+ : mState(INTERACTION_STATE_UNINITIALIZED),
+ mWaitMs(100),
+ mMinDurationMs(1400),
+ mMaxDurationMs(5650),
+ mDurationMs(0),
+ mHintManager(hint_manager) {}
+
+InteractionHandler::~InteractionHandler() {
+ Exit();
+}
+
+static int fb_idle_open(void) {
+ int fd;
+ for (auto &path : fb_idle_patch) {
+ fd = open(path.c_str(), O_RDONLY);
+ if (fd >= 0)
+ return fd;
+ }
+ ALOGE("Unable to open fb idle state path (%d)", errno);
+ return -1;
+}
+
+bool InteractionHandler::Init() {
+ std::lock_guard<std::mutex> lk(mLock);
+
+ if (mState != INTERACTION_STATE_UNINITIALIZED)
+ return true;
+
+ int fd = fb_idle_open();
+ if (fd < 0)
+ return false;
+ mIdleFd = fd;
+
+ mEventFd = eventfd(0, EFD_NONBLOCK);
+ if (mEventFd < 0) {
+ ALOGE("Unable to create event fd (%d)", errno);
+ close(mIdleFd);
+ return false;
+ }
+
+ mState = INTERACTION_STATE_IDLE;
+ mThread = std::unique_ptr<std::thread>(new std::thread(&InteractionHandler::Routine, this));
+
+ return true;
+}
+
+void InteractionHandler::Exit() {
+ std::unique_lock<std::mutex> lk(mLock);
+ if (mState == INTERACTION_STATE_UNINITIALIZED)
+ return;
+
+ AbortWaitLocked();
+ mState = INTERACTION_STATE_UNINITIALIZED;
+ lk.unlock();
+
+ mCond.notify_all();
+ mThread->join();
+
+ close(mEventFd);
+ close(mIdleFd);
+}
+
+void InteractionHandler::PerfLock() {
+ ALOGV("%s: acquiring perf lock", __func__);
+ if (!mHintManager->DoHint("INTERACTION")) {
+ ALOGE("%s: do hint INTERACTION failed", __func__);
+ }
+ ATRACE_INT("interaction_lock", 1);
+}
+
+void InteractionHandler::PerfRel() {
+ ALOGV("%s: releasing perf lock", __func__);
+ if (!mHintManager->EndHint("INTERACTION")) {
+ ALOGE("%s: end hint INTERACTION failed", __func__);
+ }
+ ATRACE_INT("interaction_lock", 0);
+}
+
+size_t InteractionHandler::CalcTimespecDiffMs(struct timespec start, struct timespec end) {
+ size_t diff_in_us = 0;
+ diff_in_us += (end.tv_sec - start.tv_sec) * MSINSEC;
+ diff_in_us += (end.tv_nsec - start.tv_nsec) / USINMS;
+ return diff_in_us;
+}
+
+void InteractionHandler::Acquire(int32_t duration) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lk(mLock);
+ if (mState == INTERACTION_STATE_UNINITIALIZED) {
+ ALOGW("%s: called while uninitialized", __func__);
+ return;
+ }
+
+ int inputDuration = duration + 650;
+ int finalDuration;
+ if (inputDuration > mMaxDurationMs)
+ finalDuration = mMaxDurationMs;
+ else if (inputDuration > mMinDurationMs)
+ finalDuration = inputDuration;
+ else
+ finalDuration = mMinDurationMs;
+
+ struct timespec cur_timespec;
+ clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
+ if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
+ size_t elapsed_time = CalcTimespecDiffMs(mLastTimespec, cur_timespec);
+ // don't hint if previous hint's duration covers this hint's duration
+ if (elapsed_time <= (mDurationMs - finalDuration)) {
+ ALOGV("%s: Previous duration (%d) cover this (%d) elapsed: %lld", __func__,
+ static_cast<int>(mDurationMs), static_cast<int>(finalDuration),
+ static_cast<long long>(elapsed_time));
+ return;
+ }
+ }
+ mLastTimespec = cur_timespec;
+ mDurationMs = finalDuration;
+
+ ALOGV("%s: input: %d final duration: %d", __func__, duration, finalDuration);
+
+ if (mState == INTERACTION_STATE_WAITING)
+ AbortWaitLocked();
+ else if (mState == INTERACTION_STATE_IDLE)
+ PerfLock();
+
+ mState = INTERACTION_STATE_INTERACTION;
+ mCond.notify_one();
+}
+
+void InteractionHandler::Release() {
+ std::lock_guard<std::mutex> lk(mLock);
+ if (mState == INTERACTION_STATE_WAITING) {
+ ATRACE_CALL();
+ PerfRel();
+ mState = INTERACTION_STATE_IDLE;
+ } else {
+ // clear any wait aborts pending in event fd
+ uint64_t val;
+ ssize_t ret = read(mEventFd, &val, sizeof(val));
+
+ ALOGW_IF(ret < 0, "%s: failed to clear eventfd (%zd, %d)", __func__, ret, errno);
+ }
+}
+
+// should be called while locked
+void InteractionHandler::AbortWaitLocked() {
+ uint64_t val = 1;
+ ssize_t ret = write(mEventFd, &val, sizeof(val));
+ if (ret != sizeof(val))
+ ALOGW("Unable to write to event fd (%zd)", ret);
+}
+
+void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) {
+ char data[MAX_LENGTH];
+ ssize_t ret;
+ struct pollfd pfd[2];
+
+ ATRACE_CALL();
+
+ ALOGV("%s: wait:%d timeout:%d", __func__, wait_ms, timeout_ms);
+
+ pfd[0].fd = mEventFd;
+ pfd[0].events = POLLIN;
+ pfd[1].fd = mIdleFd;
+ pfd[1].events = POLLPRI | POLLERR;
+
+ ret = poll(pfd, 1, wait_ms);
+ if (ret > 0) {
+ ALOGV("%s: wait aborted", __func__);
+ return;
+ } else if (ret < 0) {
+ ALOGE("%s: error in poll while waiting", __func__);
+ return;
+ }
+
+ ret = pread(mIdleFd, data, sizeof(data), 0);
+ if (!ret) {
+ ALOGE("%s: Unexpected EOF!", __func__);
+ return;
+ }
+
+ if (!strncmp(data, "idle", 4)) {
+ ALOGV("%s: already idle", __func__);
+ return;
+ }
+
+ ret = poll(pfd, 2, timeout_ms);
+ if (ret < 0)
+ ALOGE("%s: Error on waiting for idle (%zd)", __func__, ret);
+ else if (ret == 0)
+ ALOGV("%s: timed out waiting for idle", __func__);
+ else if (pfd[0].revents)
+ ALOGV("%s: wait for idle aborted", __func__);
+ else if (pfd[1].revents)
+ ALOGV("%s: idle detected", __func__);
+}
+
+void InteractionHandler::Routine() {
+ std::unique_lock<std::mutex> lk(mLock, std::defer_lock);
+
+ while (true) {
+ lk.lock();
+ mCond.wait(lk, [&] { return mState != INTERACTION_STATE_IDLE; });
+ if (mState == INTERACTION_STATE_UNINITIALIZED)
+ return;
+ mState = INTERACTION_STATE_WAITING;
+ lk.unlock();
+
+ WaitForIdle(mWaitMs, mDurationMs);
+ Release();
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
+#define POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include <perfmgr/HintManager.h>
+
+using ::android::perfmgr::HintManager;
+
+enum interaction_state {
+ INTERACTION_STATE_UNINITIALIZED,
+ INTERACTION_STATE_IDLE,
+ INTERACTION_STATE_INTERACTION,
+ INTERACTION_STATE_WAITING,
+};
+
+class InteractionHandler {
+ public:
+ InteractionHandler(std::shared_ptr<HintManager> const &hint_manager);
+ ~InteractionHandler();
+ bool Init();
+ void Exit();
+ void Acquire(int32_t duration);
+
+ private:
+ void Release();
+ void WaitForIdle(int32_t wait_ms, int32_t timeout_ms);
+ void AbortWaitLocked();
+ void Routine();
+
+ void PerfLock();
+ void PerfRel();
+
+ size_t CalcTimespecDiffMs(struct timespec start, struct timespec end);
+
+ enum interaction_state mState;
+
+ int mIdleFd;
+ int mEventFd;
+
+ int32_t mWaitMs;
+ int32_t mMinDurationMs;
+ int32_t mMaxDurationMs;
+ int32_t mDurationMs;
+
+ struct timespec mLastTimespec;
+
+ std::unique_ptr<std::thread> mThread;
+ std::mutex mLock;
+ std::condition_variable mCond;
+ std::shared_ptr<HintManager> mHintManager;
+};
+
+#endif // POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+#define LOG_TAG "android.hardware.power@1.3-service.pixel-libperfmgr"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include <mutex>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "AudioStreaming.h"
+#include "Power.h"
+#include "display-helper.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::Status;
+
+constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
+constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
+constexpr char kPowerHalInitProp[] = "vendor.powerhal.init";
+constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
+constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json";
+
+static const std::map<enum CameraStreamingMode, std::string> kCamStreamingHint = {
+ {CAMERA_STREAMING_OFF, "CAMERA_STREAMING_OFF"},
+ {CAMERA_STREAMING, "CAMERA_STREAMING"},
+ {CAMERA_STREAMING_1080P, "CAMERA_STREAMING_1080P"},
+ {CAMERA_STREAMING_60FPS, "CAMERA_STREAMING_60FPS"},
+ {CAMERA_STREAMING_4K, "CAMERA_STREAMING_4K"},
+ {CAMERA_STREAMING_SECURE, "CAMERA_STREAMING_SECURE"}};
+
+Power::Power()
+ : mHintManager(nullptr),
+ mInteractionHandler(nullptr),
+ mVRModeOn(false),
+ mSustainedPerfModeOn(false),
+ mCameraStreamingMode(CAMERA_STREAMING_OFF),
+ mReady(false) {
+ mInitThread = std::thread([this]() {
+ android::base::WaitForProperty(kPowerHalInitProp, "1");
+ mHintManager = HintManager::GetFromJSON(kPowerHalConfigPath);
+ if (!mHintManager) {
+ LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath;
+ }
+ mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager);
+ mInteractionHandler->Init();
+ std::string state = android::base::GetProperty(kPowerHalStateProp, "");
+ if (state == "CAMERA_STREAMING") {
+ ALOGI("Initialize with CAMERA_STREAMING on");
+ mHintManager->DoHint("CAMERA_STREAMING");
+ mCameraStreamingMode = CAMERA_STREAMING;
+ } else if (state == "CAMERA_STREAMING_1080P") {
+ ALOGI("Initialize CAMERA_STREAMING_1080P on");
+ mHintManager->DoHint("CAMERA_STREAMING_1080P");
+ mCameraStreamingMode = CAMERA_STREAMING_1080P;
+ } else if (state == "CAMERA_STREAMING_60FPS") {
+ ALOGI("Initialize CAMERA_STREAMING_60FPS on");
+ mHintManager->DoHint("CAMERA_STREAMING_60FPS");
+ mCameraStreamingMode = CAMERA_STREAMING_60FPS;
+ } else if (state == "CAMERA_STREAMING_4K") {
+ ALOGI("Initialize with CAMERA_STREAMING_4K on");
+ mHintManager->DoHint("CAMERA_STREAMING_4K");
+ mCameraStreamingMode = CAMERA_STREAMING_4K;
+ } else if (state == "CAMERA_STREAMING_SECURE") {
+ ALOGI("Initialize with CAMERA_STREAMING_SECURE on");
+ mHintManager->DoHint("CAMERA_STREAMING_SECURE");
+ mCameraStreamingMode = CAMERA_STREAMING_SECURE;
+ } else if (state == "SUSTAINED_PERFORMANCE") {
+ ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
+ mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+ mSustainedPerfModeOn = true;
+ } else if (state == "VR_MODE") {
+ ALOGI("Initialize with VR_MODE on");
+ mHintManager->DoHint("VR_MODE");
+ mVRModeOn = true;
+ } else if (state == "VR_SUSTAINED_PERFORMANCE") {
+ ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR_MODE on");
+ mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+ mSustainedPerfModeOn = true;
+ mVRModeOn = true;
+ } else {
+ ALOGI("Initialize PowerHAL");
+ }
+
+ state = android::base::GetProperty(kPowerHalAudioProp, "");
+ if (state == "AUDIO_LOW_LATENCY") {
+ ALOGI("Initialize with AUDIO_LOW_LATENCY on");
+ mHintManager->DoHint("AUDIO_LOW_LATENCY");
+ }
+
+ state = android::base::GetProperty(kPowerHalRenderingProp, "");
+ if (state == "EXPENSIVE_RENDERING") {
+ ALOGI("Initialize with EXPENSIVE_RENDERING on");
+ mHintManager->DoHint("EXPENSIVE_RENDERING");
+ }
+ // Now start to take powerhint
+ mReady.store(true);
+ ALOGI("PowerHAL ready to process hints");
+ });
+ mInitThread.detach();
+}
+
+// Methods from ::android::hardware::power::V1_0::IPower follow.
+Return<void> Power::setInteractive(bool /* interactive */) {
+ return Void();
+}
+
+Return<void> Power::powerHint(PowerHint_1_0 hint, int32_t data) {
+ if (!mReady) {
+ return Void();
+ }
+ ATRACE_INT(android::hardware::power::V1_0::toString(hint).c_str(), data);
+ ALOGD_IF(hint != PowerHint_1_0::INTERACTION, "%s: %d",
+ android::hardware::power::V1_0::toString(hint).c_str(), static_cast<int>(data));
+ switch (hint) {
+ case PowerHint_1_0::INTERACTION:
+ if (mVRModeOn || mSustainedPerfModeOn) {
+ ALOGV("%s: ignoring due to other active perf hints", __func__);
+ } else {
+ mInteractionHandler->Acquire(data);
+ }
+ break;
+ case PowerHint_1_0::SUSTAINED_PERFORMANCE:
+ if (data && !mSustainedPerfModeOn) {
+ if (!mVRModeOn) { // Sustained mode only.
+ mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+ } else { // Sustained + VR mode.
+ mHintManager->EndHint("VR_MODE");
+ mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+ }
+ mSustainedPerfModeOn = true;
+ } else if (!data && mSustainedPerfModeOn) {
+ mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
+ mHintManager->EndHint("SUSTAINED_PERFORMANCE");
+ if (mVRModeOn) { // Switch back to VR Mode.
+ mHintManager->DoHint("VR_MODE");
+ }
+ mSustainedPerfModeOn = false;
+ }
+ break;
+ case PowerHint_1_0::VR_MODE:
+ if (data && !mVRModeOn) {
+ if (!mSustainedPerfModeOn) { // VR mode only.
+ mHintManager->DoHint("VR_MODE");
+ } else { // Sustained + VR mode.
+ mHintManager->EndHint("SUSTAINED_PERFORMANCE");
+ mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+ }
+ mVRModeOn = true;
+ } else if (!data && mVRModeOn) {
+ mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
+ mHintManager->EndHint("VR_MODE");
+ if (mSustainedPerfModeOn) { // Switch back to sustained Mode.
+ mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+ }
+ mVRModeOn = false;
+ }
+ break;
+ case PowerHint_1_0::LAUNCH:
+ if (mVRModeOn || mSustainedPerfModeOn) {
+ ALOGV("%s: ignoring due to other active perf hints", __func__);
+ } else {
+ if (data) {
+ // Hint until canceled
+ mHintManager->DoHint("LAUNCH");
+ } else {
+ mHintManager->EndHint("LAUNCH");
+ }
+ }
+ break;
+ case PowerHint_1_0::LOW_POWER:
+ if (data) {
+ // Device in battery saver mode, enable display low power mode
+ set_display_lpm(true);
+ } else {
+ // Device exiting battery saver mode, disable display low power mode
+ set_display_lpm(false);
+ }
+ break;
+ default:
+ break;
+ }
+ return Void();
+}
+
+Return<void> Power::setFeature(Feature /*feature*/, bool /*activate*/) {
+ // Nothing to do
+ return Void();
+}
+
+Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
+ LOG(ERROR) << "getPlatformLowPowerStats not supported. Use IPowerStats HAL.";
+ _hidl_cb({}, Status::SUCCESS);
+ return Void();
+}
+
+// Methods from ::android::hardware::power::V1_1::IPower follow.
+Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
+ LOG(ERROR) << "getSubsystemLowPowerStats not supported. Use IPowerStats HAL.";
+ _hidl_cb({}, Status::SUCCESS);
+ return Void();
+}
+
+Return<void> Power::powerHintAsync(PowerHint_1_0 hint, int32_t data) {
+ // just call the normal power hint in this oneway function
+ return powerHint(hint, data);
+}
+
+// Methods from ::android::hardware::power::V1_2::IPower follow.
+Return<void> Power::powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) {
+ if (!mReady) {
+ return Void();
+ }
+
+ ATRACE_INT(android::hardware::power::V1_2::toString(hint).c_str(), data);
+ ALOGD_IF(hint >= PowerHint_1_2::AUDIO_STREAMING, "%s: %d",
+ android::hardware::power::V1_2::toString(hint).c_str(), static_cast<int>(data));
+
+ switch (hint) {
+ case PowerHint_1_2::AUDIO_LOW_LATENCY:
+ if (data) {
+ // Hint until canceled
+ mHintManager->DoHint("AUDIO_LOW_LATENCY");
+ } else {
+ mHintManager->EndHint("AUDIO_LOW_LATENCY");
+ }
+ break;
+ case PowerHint_1_2::AUDIO_STREAMING:
+ if (mVRModeOn || mSustainedPerfModeOn) {
+ ALOGV("%s: ignoring due to other active perf hints", __func__);
+ } else {
+ if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::AUDIO_STREAMING_ON)) {
+ mHintManager->DoHint("AUDIO_STREAMING");
+ } else if (data ==
+ static_cast<int32_t>(AUDIO_STREAMING_HINT::AUDIO_STREAMING_OFF)) {
+ mHintManager->EndHint("AUDIO_STREAMING");
+ } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_SHORT)) {
+ mHintManager->DoHint("TPU_BOOST",
+ std::chrono::milliseconds(TPU_HINT_DURATION_MS::SHORT));
+ } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_LONG)) {
+ mHintManager->DoHint("TPU_BOOST",
+ std::chrono::milliseconds(TPU_HINT_DURATION_MS::LONG));
+ } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_OFF)) {
+ mHintManager->EndHint("TPU_BOOST");
+ } else {
+ ALOGE("AUDIO STREAMING INVALID DATA: %d", data);
+ }
+ }
+ break;
+ case PowerHint_1_2::CAMERA_LAUNCH:
+ if (data > 0) {
+ mHintManager->DoHint("CAMERA_LAUNCH");
+ } else if (data == 0) {
+ mHintManager->EndHint("CAMERA_LAUNCH");
+ } else {
+ ALOGE("CAMERA LAUNCH INVALID DATA: %d", data);
+ }
+ break;
+ case PowerHint_1_2::CAMERA_STREAMING: {
+ const enum CameraStreamingMode mode = static_cast<enum CameraStreamingMode>(data);
+ if (mode < CAMERA_STREAMING_OFF || mode >= CAMERA_STREAMING_MAX) {
+ ALOGE("CAMERA STREAMING INVALID Mode: %d", mode);
+ break;
+ }
+
+ if (mCameraStreamingMode == mode)
+ break;
+
+ // turn it off first if any previous hint.
+ if ((mCameraStreamingMode != CAMERA_STREAMING_OFF)) {
+ const auto modeValue = kCamStreamingHint.at(mCameraStreamingMode);
+ mHintManager->EndHint(modeValue);
+ if ((mCameraStreamingMode != CAMERA_STREAMING_SECURE)) {
+ // Boost 1s for tear down if not secure streaming use case
+ mHintManager->DoHint("CAMERA_LAUNCH", std::chrono::seconds(1));
+ }
+ }
+
+ if (mode != CAMERA_STREAMING_OFF) {
+ const auto hintValue = kCamStreamingHint.at(mode);
+ mHintManager->DoHint(hintValue);
+ }
+
+ mCameraStreamingMode = mode;
+ const auto prop = (mCameraStreamingMode == CAMERA_STREAMING_OFF)
+ ? ""
+ : kCamStreamingHint.at(mode).c_str();
+ if (!android::base::SetProperty(kPowerHalStateProp, prop)) {
+ ALOGE("%s: could set powerHAL state %s property", __func__, prop);
+ }
+ break;
+ }
+ case PowerHint_1_2::CAMERA_SHOT:
+ if (data > 0) {
+ mHintManager->DoHint("CAMERA_SHOT", std::chrono::milliseconds(data));
+ } else if (data == 0) {
+ mHintManager->EndHint("CAMERA_SHOT");
+ } else {
+ ALOGE("CAMERA SHOT INVALID DATA: %d", data);
+ }
+ break;
+ default:
+ return powerHint(static_cast<PowerHint_1_0>(hint), data);
+ }
+ return Void();
+}
+
+// Methods from ::android::hardware::power::V1_3::IPower follow.
+Return<void> Power::powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) {
+ if (!mReady) {
+ return Void();
+ }
+
+ if (hint == PowerHint_1_3::EXPENSIVE_RENDERING) {
+ ATRACE_INT(android::hardware::power::V1_3::toString(hint).c_str(), data);
+ if (mVRModeOn || mSustainedPerfModeOn) {
+ ALOGV("%s: ignoring due to other active perf hints", __func__);
+ } else {
+ if (data > 0) {
+ mHintManager->DoHint("EXPENSIVE_RENDERING");
+ } else {
+ mHintManager->EndHint("EXPENSIVE_RENDERING");
+ }
+ }
+ } else {
+ return powerHintAsync_1_2(static_cast<PowerHint_1_2>(hint), data);
+ }
+ return Void();
+}
+
+constexpr const char *boolToString(bool b) {
+ return b ? "true" : "false";
+}
+
+Return<void> Power::debug(const hidl_handle &handle, const hidl_vec<hidl_string> &) {
+ if (handle != nullptr && handle->numFds >= 1 && mReady) {
+ int fd = handle->data[0];
+
+ std::string buf(android::base::StringPrintf(
+ "HintManager Running: %s\n"
+ "VRMode: %s\n"
+ "CameraStreamingMode: %s\n"
+ "SustainedPerformanceMode: %s\n",
+ boolToString(mHintManager->IsRunning()), boolToString(mVRModeOn),
+ kCamStreamingHint.at(mCameraStreamingMode).c_str(),
+ boolToString(mSustainedPerfModeOn)));
+ // Dump nodes through libperfmgr
+ mHintManager->DumpToFd(fd);
+ if (!android::base::WriteStringToFd(buf, fd)) {
+ PLOG(ERROR) << "Failed to dump state to fd";
+ }
+ fsync(fd);
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace power
+} // namespace hardware
+} // namespace android
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef POWER_LIBPERFMGR_POWER_H_
+#define POWER_LIBPERFMGR_POWER_H_
+
+#include <atomic>
+#include <memory>
+#include <thread>
+
+#include <android/hardware/power/1.3/IPower.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <perfmgr/HintManager.h>
+
+#include "CameraMode.h"
+#include "InteractionHandler.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_3 {
+namespace implementation {
+
+using ::InteractionHandler;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_3::IPower;
+using PowerHint_1_0 = ::android::hardware::power::V1_0::PowerHint;
+using PowerHint_1_2 = ::android::hardware::power::V1_2::PowerHint;
+using PowerHint_1_3 = ::android::hardware::power::V1_3::PowerHint;
+using ::android::perfmgr::HintManager;
+
+class Power : public IPower {
+ public:
+ // Methods from ::android::hardware::power::V1_0::IPower follow.
+
+ Power();
+
+ Return<void> setInteractive(bool /* interactive */) override;
+ Return<void> powerHint(PowerHint_1_0 hint, int32_t data) override;
+ Return<void> setFeature(Feature feature, bool activate) override;
+ Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::power::V1_1::IPower follow.
+ Return<void> getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) override;
+ Return<void> powerHintAsync(PowerHint_1_0 hint, int32_t data) override;
+
+ // Methods from ::android::hardware::power::V1_2::IPower follow.
+ Return<void> powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) override;
+
+ // Methods from ::android::hardware::power::V1_3::IPower follow.
+ Return<void> powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) override;
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+ Return<void> debug(const hidl_handle &fd, const hidl_vec<hidl_string> &args) override;
+
+ private:
+ std::shared_ptr<HintManager> mHintManager;
+ std::unique_ptr<InteractionHandler> mInteractionHandler;
+ std::atomic<bool> mVRModeOn;
+ std::atomic<bool> mSustainedPerfModeOn;
+ std::atomic<enum CameraStreamingMode> mCameraStreamingMode;
+ std::atomic<bool> mReady;
+ std::thread mInitThread;
+};
+
+} // namespace implementation
+} // namespace V1_3
+} // namespace power
+} // namespace hardware
+} // namespace android
+
+#endif // POWER_LIBPERFMGR_POWER_H_
--- /dev/null
+service vendor.power-hal-1-3 /vendor/bin/hw/android.hardware.power@1.3-service.pixel-libperfmgr
+ class hal
+ user root
+ group system
+ priority -20
+ interface android.hardware.power@1.0::IPower default
+ interface android.hardware.power@1.1::IPower default
+ interface android.hardware.power@1.2::IPower default
+ interface android.hardware.power@1.3::IPower default
+
+# restart powerHAL when framework died
+on property:init.svc.zygote=restarting && property:vendor.powerhal.state=*
+ setprop vendor.powerhal.state ""
+ setprop vendor.powerhal.audio ""
+ setprop vendor.powerhal.rendering ""
+ restart vendor.power-hal-1-3
+
+# restart powerHAL when cameraHAL died
+on property:init.svc.vendor.camera-provider-2-4=restarting && property:vendor.powerhal.state=CAMERA_STREAMING
+ setprop vendor.powerhal.state ""
+ restart vendor.power-hal-1-3
+
+# restart powerHAL when audioHAL died
+on property:init.svc.vendor.audio-hal-2-0=restarting && property:vendor.powerhal.audio=AUDIO_LOW_LATENCY
+ setprop vendor.powerhal.audio ""
+ restart vendor.power-hal-1-3
--- /dev/null
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.power</name>
+ <transport>hwbinder</transport>
+ <version>1.3</version>
+ <interface>
+ <name>IPower</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NIDEBUG 0
+#define LOG_TAG "android.hardware.power@1.3-service.pixel-libperfmgr"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/log.h>
+
+#include "display-helper.h"
+
+#define DAEMON_SOCKET "pps"
+
+static int daemon_socket = -1;
+
+static int connectPPDaemon() {
+ // Setup socket connection, if not already done.
+ if (daemon_socket < 0)
+ daemon_socket =
+ socket_local_client(DAEMON_SOCKET, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+
+ if (daemon_socket < 0) {
+ ALOGE("Connecting to socket failed: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int ppdComm(const char *cmd) {
+ int ret = -1;
+
+ ret = connectPPDaemon();
+ if (ret < 0)
+ return ret;
+
+ ret = write(daemon_socket, cmd, strlen(cmd));
+ if (ret < 0) {
+ ALOGE("Failed to send data over socket, %s", strerror(errno));
+ return ret;
+ }
+ return 0;
+}
+
+void set_display_lpm(int enable) {
+ ALOGI("set_display_lpm state: %d", enable);
+ if (enable) {
+ ppdComm("foss:on");
+ } else {
+ ppdComm("foss:off");
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef POWER_LIBPERFMGR_DISPLAY_HELPER_H_
+#define POWER_LIBPERFMGR_DISPLAY_HELPER_H_
+
+enum display_lpm_state {
+ DISPLAY_LPM_OFF = 0,
+ DISPLAY_LPM_ON,
+ DISPLAY_LPM_UNKNOWN,
+};
+
+void set_display_lpm(int enable);
+
+#endif // POWER_LIBPERFMGR_DISPLAY_HELPER_H_
--- /dev/null
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.power@1.3-service.pixel-libperfmgr"
+
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Power.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::V1_3::IPower;
+using android::hardware::power::V1_3::implementation::Power;
+
+int main(int /* argc */, char ** /* argv */) {
+ ALOGI("Power HAL Service 1.3 for Pixel is starting.");
+
+ android::sp<IPower> service = new Power();
+ if (service == nullptr) {
+ ALOGE("Can not create an instance of Power HAL Iface, exiting.");
+ return 1;
+ }
+ android::hardware::setMinSchedulerPolicy(service, SCHED_NORMAL, -20);
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ status_t status = service->registerAsService();
+ if (status != OK) {
+ ALOGE("Could not register service for Power HAL Iface (%d), exiting.", status);
+ return 1;
+ }
+
+ ALOGI("Power Service is ready");
+ joinRpcThreadpool();
+
+ // In normal operation, we don't expect the thread pool to exit
+ ALOGE("Power Service is shutting down");
+ return 1;
+}