diff --git a/hidl/power-libperfmgr/Android.bp b/hidl/power-libperfmgr/Android.bp new file mode 100644 index 00000000..7874d10b --- /dev/null +++ b/hidl/power-libperfmgr/Android.bp @@ -0,0 +1,47 @@ +// +// 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, +} diff --git a/hidl/power-libperfmgr/AudioStreaming.h b/hidl/power-libperfmgr/AudioStreaming.h new file mode 100644 index 00000000..d8772d53 --- /dev/null +++ b/hidl/power-libperfmgr/AudioStreaming.h @@ -0,0 +1,30 @@ +/* + * 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_ diff --git a/hidl/power-libperfmgr/CameraMode.h b/hidl/power-libperfmgr/CameraMode.h new file mode 100644 index 00000000..1e056231 --- /dev/null +++ b/hidl/power-libperfmgr/CameraMode.h @@ -0,0 +1,30 @@ +/* + * 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_ diff --git a/hidl/power-libperfmgr/InteractionHandler.cpp b/hidl/power-libperfmgr/InteractionHandler.cpp new file mode 100644 index 00000000..da6a9173 --- /dev/null +++ b/hidl/power-libperfmgr/InteractionHandler.cpp @@ -0,0 +1,251 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "InteractionHandler.h" + +#define MAX_LENGTH 64 + +#define MSINSEC 1000L +#define USINMS 1000000L + +static const std::vector fb_idle_patch = {"/sys/class/drm/card0/device/idle_state", + "/sys/class/graphics/fb0/idle_state"}; + +InteractionHandler::InteractionHandler(std::shared_ptr 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 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(new std::thread(&InteractionHandler::Routine, this)); + + return true; +} + +void InteractionHandler::Exit() { + std::unique_lock 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 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(mDurationMs), static_cast(finalDuration), + static_cast(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 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 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(); + } +} diff --git a/hidl/power-libperfmgr/InteractionHandler.h b/hidl/power-libperfmgr/InteractionHandler.h new file mode 100644 index 00000000..ba767f14 --- /dev/null +++ b/hidl/power-libperfmgr/InteractionHandler.h @@ -0,0 +1,74 @@ +/* + * 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 +#include +#include +#include +#include + +#include + +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 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 mThread; + std::mutex mLock; + std::condition_variable mCond; + std::shared_ptr mHintManager; +}; + +#endif // POWER_LIBPERFMGR_INTERACTIONHANDLER_H_ diff --git a/hidl/power-libperfmgr/Power.cpp b/hidl/power-libperfmgr/Power.cpp new file mode 100644 index 00000000..f199bfb2 --- /dev/null +++ b/hidl/power-libperfmgr/Power.cpp @@ -0,0 +1,390 @@ +/* + * 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 +#include +#include +#include +#include + +#include + +#include +#include + +#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 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(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 Power::setInteractive(bool /* interactive */) { + return Void(); +} + +Return 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(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 Power::setFeature(Feature /*feature*/, bool /*activate*/) { + // Nothing to do + return Void(); +} + +Return 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 Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) { + LOG(ERROR) << "getSubsystemLowPowerStats not supported. Use IPowerStats HAL."; + _hidl_cb({}, Status::SUCCESS); + return Void(); +} + +Return 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 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(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(AUDIO_STREAMING_HINT::AUDIO_STREAMING_ON)) { + mHintManager->DoHint("AUDIO_STREAMING"); + } else if (data == + static_cast(AUDIO_STREAMING_HINT::AUDIO_STREAMING_OFF)) { + mHintManager->EndHint("AUDIO_STREAMING"); + } else if (data == static_cast(AUDIO_STREAMING_HINT::TPU_BOOST_SHORT)) { + mHintManager->DoHint("TPU_BOOST", + std::chrono::milliseconds(TPU_HINT_DURATION_MS::SHORT)); + } else if (data == static_cast(AUDIO_STREAMING_HINT::TPU_BOOST_LONG)) { + mHintManager->DoHint("TPU_BOOST", + std::chrono::milliseconds(TPU_HINT_DURATION_MS::LONG)); + } else if (data == static_cast(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(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(hint), data); + } + return Void(); +} + +// Methods from ::android::hardware::power::V1_3::IPower follow. +Return 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(hint), data); + } + return Void(); +} + +constexpr const char *boolToString(bool b) { + return b ? "true" : "false"; +} + +Return Power::debug(const hidl_handle &handle, const hidl_vec &) { + 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 diff --git a/hidl/power-libperfmgr/Power.h b/hidl/power-libperfmgr/Power.h new file mode 100644 index 00000000..b43fecd7 --- /dev/null +++ b/hidl/power-libperfmgr/Power.h @@ -0,0 +1,88 @@ +/* + * 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 +#include +#include + +#include +#include +#include +#include + +#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 setInteractive(bool /* interactive */) override; + Return powerHint(PowerHint_1_0 hint, int32_t data) override; + Return setFeature(Feature feature, bool activate) override; + Return getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override; + + // Methods from ::android::hardware::power::V1_1::IPower follow. + Return getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) override; + Return powerHintAsync(PowerHint_1_0 hint, int32_t data) override; + + // Methods from ::android::hardware::power::V1_2::IPower follow. + Return powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) override; + + // Methods from ::android::hardware::power::V1_3::IPower follow. + Return powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) override; + + // Methods from ::android::hidl::base::V1_0::IBase follow. + Return debug(const hidl_handle &fd, const hidl_vec &args) override; + + private: + std::shared_ptr mHintManager; + std::unique_ptr mInteractionHandler; + std::atomic mVRModeOn; + std::atomic mSustainedPerfModeOn; + std::atomic mCameraStreamingMode; + std::atomic mReady; + std::thread mInitThread; +}; + +} // namespace implementation +} // namespace V1_3 +} // namespace power +} // namespace hardware +} // namespace android + +#endif // POWER_LIBPERFMGR_POWER_H_ diff --git a/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel-libperfmgr.rc b/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel-libperfmgr.rc new file mode 100644 index 00000000..6179f6e1 --- /dev/null +++ b/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel-libperfmgr.rc @@ -0,0 +1,26 @@ +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 diff --git a/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel.xml b/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel.xml new file mode 100644 index 00000000..e52398c0 --- /dev/null +++ b/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel.xml @@ -0,0 +1,11 @@ + + + android.hardware.power + hwbinder + 1.3 + + IPower + default + + + diff --git a/hidl/power-libperfmgr/display-helper.cpp b/hidl/power-libperfmgr/display-helper.cpp new file mode 100644 index 00000000..2369c631 --- /dev/null +++ b/hidl/power-libperfmgr/display-helper.cpp @@ -0,0 +1,74 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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"); + } +} diff --git a/hidl/power-libperfmgr/display-helper.h b/hidl/power-libperfmgr/display-helper.h new file mode 100644 index 00000000..70b96975 --- /dev/null +++ b/hidl/power-libperfmgr/display-helper.h @@ -0,0 +1,28 @@ +/* + * 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_ diff --git a/hidl/power-libperfmgr/service.cpp b/hidl/power-libperfmgr/service.cpp new file mode 100644 index 00000000..7bcc9078 --- /dev/null +++ b/hidl/power-libperfmgr/service.cpp @@ -0,0 +1,59 @@ +/* + * 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 +#include + +#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 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; +}