diff --git a/Android.mk b/Android.mk index fc3385bf..0ee18ab3 100644 --- a/Android.mk +++ b/Android.mk @@ -36,6 +36,7 @@ include $(SAM_ROOT)/wifiloader/Android.mk endif ifeq ($(BOARD_VENDOR),samsung) +include $(SAM_ROOT)/aidl/Android.mk include $(SAM_ROOT)/audio/Android.mk include $(SAM_ROOT)/doze/Android.mk include $(SAM_ROOT)/hidl/Android.mk diff --git a/aidl/Android.mk b/aidl/Android.mk new file mode 100644 index 00000000..26e32a7a --- /dev/null +++ b/aidl/Android.mk @@ -0,0 +1,17 @@ +# +# Copyright (C) 2019 The LineageOS 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. +# + +include $(call all-subdir-makefiles) diff --git a/aidl/power-libperfmgr/Android.bp b/aidl/power-libperfmgr/Android.bp new file mode 100644 index 00000000..f2f4a46b --- /dev/null +++ b/aidl/power-libperfmgr/Android.bp @@ -0,0 +1,93 @@ +// +// 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. + +soong_namespace { + imports: [ + "hardware/google/pixel", + "hardware/google/interfaces", + ], +} + +cc_library { + name: "libdisppower-pixel", + proprietary: true, + srcs: [ + "disp-power/DisplayLowPower.cpp", + "disp-power/InteractionHandler.cpp", + ], + shared_libs: [ + "libbase", + "libcutils", + "liblog", + "libperfmgr", + "libutils", + ], +} + +cc_library_headers { + name: "pixel_power_headers", + vendor: true, + export_include_dirs: ["hidl"], +} + +cc_binary { + name: "android.hardware.power@1.3-service.pixel-libperfmgr", + relative_install_path: "hw", + vintf_fragments: ["hidl/android.hardware.power@1.3-service.pixel.xml"], + init_rc: ["hidl/android.hardware.power@1.3-service.pixel-libperfmgr.rc"], + srcs: ["hidl/service.cpp", "hidl/Power.cpp"], + cflags: [ + "-Wall", + "-Werror", + ], + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "libutils", + "libcutils", + "android.hardware.power@1.0", + "android.hardware.power@1.1", + "android.hardware.power@1.2", + "android.hardware.power@1.3", + "libdisppower-pixel", + "libperfmgr", + ], + proprietary: true, +} + +cc_binary { + name: "android.hardware.power-service.pixel-libperfmgr", + relative_install_path: "hw", + init_rc: ["aidl/android.hardware.power-service.pixel-libperfmgr.rc"], + vintf_fragments: ["aidl/android.hardware.power-service.pixel.xml"], + vendor: true, + shared_libs: [ + "android.hardware.power-ndk_platform", + "libbase", + "libcutils", + "liblog", + "libutils", + "libbinder_ndk", + "libdisppower-pixel", + "libperfmgr", + "pixel-power-ext-ndk_platform", + ], + srcs: [ + "aidl/service.cpp", + "aidl/Power.cpp", + "aidl/PowerExt.cpp", + ], +} diff --git a/aidl/power-libperfmgr/InteractionHandler.cpp b/aidl/power-libperfmgr/InteractionHandler.cpp new file mode 100644 index 00000000..1826958e --- /dev/null +++ b/aidl/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@-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/aidl/power-libperfmgr/InteractionHandler.h b/aidl/power-libperfmgr/InteractionHandler.h new file mode 100644 index 00000000..ba767f14 --- /dev/null +++ b/aidl/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/aidl/power-libperfmgr/Power.cpp b/aidl/power-libperfmgr/Power.cpp new file mode 100644 index 00000000..d944cf40 --- /dev/null +++ b/aidl/power-libperfmgr/Power.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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-service.pixel-libperfmgr" + +#include "Power.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "disp-power/DisplayLowPower.h" + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +constexpr char kPowerHalStateProp[] = "vendor.powerhal.state"; +constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio"; +constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering"; + +Power::Power(std::shared_ptr hm, std::shared_ptr dlpw) + : mHintManager(hm), + mDisplayLowPower(dlpw), + mInteractionHandler(nullptr), + mVRModeOn(false), + mSustainedPerfModeOn(false) { + mInteractionHandler = std::make_unique(mHintManager); + mInteractionHandler->Init(); + + std::string state = ::android::base::GetProperty(kPowerHalStateProp, ""); + if (state == "SUSTAINED_PERFORMANCE") { + ALOGI("Initialize with SUSTAINED_PERFORMANCE on"); + mHintManager->DoHint("SUSTAINED_PERFORMANCE"); + mSustainedPerfModeOn = true; + } else if (state == "VR") { + ALOGI("Initialize with VR on"); + mHintManager->DoHint(state); + mVRModeOn = true; + } else if (state == "VR_SUSTAINED_PERFORMANCE") { + ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR on"); + mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE"); + mSustainedPerfModeOn = true; + mVRModeOn = true; + } else { + ALOGI("Initialize PowerHAL"); + } + + state = ::android::base::GetProperty(kPowerHalAudioProp, ""); + if (state == "AUDIO_STREAMING_LOW_LATENCY") { + ALOGI("Initialize with AUDIO_LOW_LATENCY on"); + mHintManager->DoHint(state); + } + + state = ::android::base::GetProperty(kPowerHalRenderingProp, ""); + if (state == "EXPENSIVE_RENDERING") { + ALOGI("Initialize with EXPENSIVE_RENDERING on"); + mHintManager->DoHint("EXPENSIVE_RENDERING"); + } + + // Now start to take powerhint + ALOGI("PowerHAL ready to process hints"); +} + +ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) { + LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled; + ATRACE_INT(toString(type).c_str(), enabled); + switch (type) { + case Mode::LOW_POWER: + mDisplayLowPower->SetDisplayLowPower(enabled); + if (enabled) { + mHintManager->DoHint(toString(type)); + } else { + mHintManager->EndHint(toString(type)); + } + break; + case Mode::SUSTAINED_PERFORMANCE: + if (enabled && !mSustainedPerfModeOn) { + if (!mVRModeOn) { // Sustained mode only. + mHintManager->DoHint("SUSTAINED_PERFORMANCE"); + } else { // Sustained + VR mode. + mHintManager->EndHint("VR"); + mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE"); + } + mSustainedPerfModeOn = true; + } else if (!enabled && mSustainedPerfModeOn) { + mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE"); + mHintManager->EndHint("SUSTAINED_PERFORMANCE"); + if (mVRModeOn) { // Switch back to VR Mode. + mHintManager->DoHint("VR"); + } + mSustainedPerfModeOn = false; + } + break; + case Mode::VR: + if (enabled && !mVRModeOn) { + if (!mSustainedPerfModeOn) { // VR mode only. + mHintManager->DoHint("VR"); + } else { // Sustained + VR mode. + mHintManager->EndHint("SUSTAINED_PERFORMANCE"); + mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE"); + } + mVRModeOn = true; + } else if (!enabled && mVRModeOn) { + mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE"); + mHintManager->EndHint("VR"); + if (mSustainedPerfModeOn) { // Switch back to sustained Mode. + mHintManager->DoHint("SUSTAINED_PERFORMANCE"); + } + mVRModeOn = false; + } + break; + case Mode::LAUNCH: + if (mVRModeOn || mSustainedPerfModeOn) { + break; + } + [[fallthrough]]; + case Mode::DOUBLE_TAP_TO_WAKE: + [[fallthrough]]; + case Mode::FIXED_PERFORMANCE: + [[fallthrough]]; + case Mode::EXPENSIVE_RENDERING: + [[fallthrough]]; + case Mode::INTERACTIVE: + [[fallthrough]]; + case Mode::DEVICE_IDLE: + [[fallthrough]]; + case Mode::DISPLAY_INACTIVE: + [[fallthrough]]; + case Mode::AUDIO_STREAMING_LOW_LATENCY: + [[fallthrough]]; + case Mode::CAMERA_STREAMING_SECURE: + [[fallthrough]]; + case Mode::CAMERA_STREAMING_LOW: + [[fallthrough]]; + case Mode::CAMERA_STREAMING_MID: + [[fallthrough]]; + case Mode::CAMERA_STREAMING_HIGH: + [[fallthrough]]; + default: + if (enabled) { + mHintManager->DoHint(toString(type)); + } else { + mHintManager->EndHint(toString(type)); + } + break; + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Power::isModeSupported(Mode type, bool *_aidl_return) { + bool supported = mHintManager->IsHintSupported(toString(type)); + // LOW_POWER handled insides PowerHAL specifically + if (type == Mode::LOW_POWER) { + supported = true; + } + LOG(INFO) << "Power mode " << toString(type) << " isModeSupported: " << supported; + *_aidl_return = supported; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) { + LOG(DEBUG) << "Power setBoost: " << toString(type) << " duration: " << durationMs; + ATRACE_INT(toString(type).c_str(), durationMs); + switch (type) { + case Boost::INTERACTION: + if (mVRModeOn || mSustainedPerfModeOn) { + break; + } + mInteractionHandler->Acquire(durationMs); + break; + case Boost::DISPLAY_UPDATE_IMMINENT: + [[fallthrough]]; + case Boost::ML_ACC: + [[fallthrough]]; + case Boost::AUDIO_LAUNCH: + [[fallthrough]]; + case Boost::CAMERA_LAUNCH: + [[fallthrough]]; + case Boost::CAMERA_SHOT: + [[fallthrough]]; + default: + if (mVRModeOn || mSustainedPerfModeOn) { + break; + } + if (durationMs > 0) { + mHintManager->DoHint(toString(type), std::chrono::milliseconds(durationMs)); + } else if (durationMs == 0) { + mHintManager->DoHint(toString(type)); + } else { + mHintManager->EndHint(toString(type)); + } + break; + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool *_aidl_return) { + bool supported = mHintManager->IsHintSupported(toString(type)); + LOG(INFO) << "Power boost " << toString(type) << " isBoostSupported: " << supported; + *_aidl_return = supported; + return ndk::ScopedAStatus::ok(); +} + +constexpr const char *boolToString(bool b) { + return b ? "true" : "false"; +} + +binder_status_t Power::dump(int fd, const char **, uint32_t) { + std::string buf(::android::base::StringPrintf( + "HintManager Running: %s\n" + "VRMode: %s\n" + "SustainedPerformanceMode: %s\n", + boolToString(mHintManager->IsRunning()), boolToString(mVRModeOn), + 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 STATUS_OK; +} + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/aidl/power-libperfmgr/Power.h b/aidl/power-libperfmgr/Power.h new file mode 100644 index 00000000..8b90cb48 --- /dev/null +++ b/aidl/power-libperfmgr/Power.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include "disp-power/DisplayLowPower.h" +#include "disp-power/InteractionHandler.h" + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +using ::InteractionHandler; +using ::aidl::android::hardware::power::Boost; +using ::aidl::android::hardware::power::Mode; +using ::android::perfmgr::HintManager; + +class Power : public ::aidl::android::hardware::power::BnPower { + public: + Power(std::shared_ptr hm, std::shared_ptr dlpw); + ndk::ScopedAStatus setMode(Mode type, bool enabled) override; + ndk::ScopedAStatus isModeSupported(Mode type, bool *_aidl_return) override; + ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override; + ndk::ScopedAStatus isBoostSupported(Boost type, bool *_aidl_return) override; + binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; + + private: + std::shared_ptr mHintManager; + std::shared_ptr mDisplayLowPower; + std::unique_ptr mInteractionHandler; + std::atomic mVRModeOn; + std::atomic mSustainedPerfModeOn; +}; + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/aidl/power-libperfmgr/PowerExt.cpp b/aidl/power-libperfmgr/PowerExt.cpp new file mode 100644 index 00000000..24e855d3 --- /dev/null +++ b/aidl/power-libperfmgr/PowerExt.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 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-service.pixel.ext-libperfmgr" + +#include "PowerExt.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +ndk::ScopedAStatus PowerExt::setMode(const std::string &mode, bool enabled) { + LOG(DEBUG) << "PowerExt setMode: " << mode << " to: " << enabled; + ATRACE_INT(mode.c_str(), enabled); + + if (enabled) { + mHintManager->DoHint(mode); + } else { + mHintManager->EndHint(mode); + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerExt::isModeSupported(const std::string &mode, bool *_aidl_return) { + bool supported = mHintManager->IsHintSupported(mode); + LOG(INFO) << "PowerExt mode " << mode << " isModeSupported: " << supported; + *_aidl_return = supported; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerExt::setBoost(const std::string &boost, int32_t durationMs) { + LOG(DEBUG) << "PowerExt setBoost: " << boost << " duration: " << durationMs; + ATRACE_INT(boost.c_str(), durationMs); + + if (durationMs > 0) { + mHintManager->DoHint(boost, std::chrono::milliseconds(durationMs)); + } else if (durationMs == 0) { + mHintManager->DoHint(boost); + } else { + mHintManager->EndHint(boost); + } + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus PowerExt::isBoostSupported(const std::string &boost, bool *_aidl_return) { + bool supported = mHintManager->IsHintSupported(boost); + LOG(INFO) << "PowerExt boost " << boost << " isBoostSupported: " << supported; + *_aidl_return = supported; + return ndk::ScopedAStatus::ok(); +} + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/aidl/power-libperfmgr/PowerExt.h b/aidl/power-libperfmgr/PowerExt.h new file mode 100644 index 00000000..65cec2c1 --- /dev/null +++ b/aidl/power-libperfmgr/PowerExt.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include "disp-power/DisplayLowPower.h" + +namespace aidl { +namespace google { +namespace hardware { +namespace power { +namespace impl { +namespace pixel { + +using ::android::perfmgr::HintManager; + +class PowerExt : public ::aidl::google::hardware::power::extension::pixel::BnPowerExt { + public: + PowerExt(std::shared_ptr hm, std::shared_ptr dlpw) + : mHintManager(hm), mDisplayLowPower(dlpw) {} + ndk::ScopedAStatus setMode(const std::string &mode, bool enabled) override; + ndk::ScopedAStatus isModeSupported(const std::string &mode, bool *_aidl_return) override; + ndk::ScopedAStatus setBoost(const std::string &boost, int32_t durationMs) override; + ndk::ScopedAStatus isBoostSupported(const std::string &boost, bool *_aidl_return) override; + + private: + std::shared_ptr mHintManager; + std::shared_ptr mDisplayLowPower; +}; + +} // namespace pixel +} // namespace impl +} // namespace power +} // namespace hardware +} // namespace google +} // namespace aidl diff --git a/aidl/power-libperfmgr/android.hardware.power-service.pixel-libperfmgr.rc b/aidl/power-libperfmgr/android.hardware.power-service.pixel-libperfmgr.rc new file mode 100644 index 00000000..ef15b123 --- /dev/null +++ b/aidl/power-libperfmgr/android.hardware.power-service.pixel-libperfmgr.rc @@ -0,0 +1,29 @@ +service vendor.power-hal-aidl /vendor/bin/hw/android.hardware.power-service.pixel-libperfmgr + class hal + user root + group system + priority -20 + +on late-fs + start vendor.power-hal-aidl + +# 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-aidl + +# restart powerHAL when audioHAL died +on property:init.svc.vendor.audio-hal-2-0=restarting && property:vendor.powerhal.audio=AUDIO_STREAMING_LOW_LATENCY + setprop vendor.powerhal.audio "" + restart vendor.power-hal-aidl + +# Clean up after b/163539793 resolved +on property:vendor.powerhal.dalvik.vm.dex2oat-threads=* + setprop dalvik.vm.dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads} + setprop dalvik.vm.restore-dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads} + +on property:vendor.powerhal.dalvik.vm.dex2oat-cpu-set=* + setprop dalvik.vm.dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set} + setprop dalvik.vm.restore-dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set} diff --git a/aidl/power-libperfmgr/android.hardware.power-service.pixel.xml b/aidl/power-libperfmgr/android.hardware.power-service.pixel.xml new file mode 100644 index 00000000..caf6ea2d --- /dev/null +++ b/aidl/power-libperfmgr/android.hardware.power-service.pixel.xml @@ -0,0 +1,6 @@ + + + android.hardware.power + IPower/default + + diff --git a/aidl/power-libperfmgr/device.mk b/aidl/power-libperfmgr/device.mk new file mode 100644 index 00000000..c8485975 --- /dev/null +++ b/aidl/power-libperfmgr/device.mk @@ -0,0 +1,5 @@ +BOARD_SEPOLICY_DIRS += hardware/google/pixel-sepolicy/power-libperfmgr + +# power HAL +PRODUCT_PACKAGES += \ + android.hardware.power-service.pixel-libperfmgr diff --git a/aidl/power-libperfmgr/service.cpp b/aidl/power-libperfmgr/service.cpp new file mode 100644 index 00000000..aeb63564 --- /dev/null +++ b/aidl/power-libperfmgr/service.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 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-service.pixel-libperfmgr" + +#include + +#include +#include +#include +#include + +#include "Power.h" +#include "PowerExt.h" +#include "disp-power/DisplayLowPower.h" + +using aidl::google::hardware::power::impl::pixel::Power; +using aidl::google::hardware::power::impl::pixel::PowerExt; +using ::android::perfmgr::HintManager; + +constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json"; +constexpr char kPowerHalInitProp[] = "vendor.powerhal.init"; + +int main() { + LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting."; + + // Parse config but do not start the looper + std::shared_ptr hm = HintManager::GetFromJSON(kPowerHalConfigPath, false); + if (!hm) { + LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath; + } + + std::shared_ptr dlpw = std::make_shared(); + + // single thread + ABinderProcess_setThreadPoolMaxThreadCount(0); + + // core service + std::shared_ptr pw = ndk::SharedRefBase::make(hm, dlpw); + ndk::SpAIBinder pwBinder = pw->asBinder(); + + // extension service + std::shared_ptr pwExt = ndk::SharedRefBase::make(hm, dlpw); + + // attach the extension to the same binder we will be registering + CHECK(STATUS_OK == AIBinder_setExtension(pwBinder.get(), pwExt->asBinder().get())); + + const std::string instance = std::string() + Power::descriptor + "/default"; + binder_status_t status = AServiceManager_addService(pw->asBinder().get(), instance.c_str()); + CHECK(status == STATUS_OK); + LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is started."; + + std::thread initThread([&]() { + ::android::base::WaitForProperty(kPowerHalInitProp, "1"); + hm->Start(); + dlpw->Init(); + }); + initThread.detach(); + + ABinderProcess_joinThreadPool(); + + // should not reach + LOG(ERROR) << "Pixel Power HAL AIDL Service with Extension just died."; + return EXIT_FAILURE; +}