wahoo: power: switch to libperfmgr for powerhint

Test: boot and do powerhint
Bug: 62041945
Change-Id: I7de1d2bf377fb46162171a084fca3413b1067d3b
diff --git a/device.mk b/device.mk
index e8f48d3..d2913c5 100755
--- a/device.mk
+++ b/device.mk
@@ -169,10 +169,10 @@
 
 # power HAL
 PRODUCT_PACKAGES += \
-    android.hardware.power@1.2-service.wahoo
+    android.hardware.power@1.2-service.wahoo-libperfmgr
 
 PRODUCT_COPY_FILES += \
-    $(LOCAL_PATH)/powerhint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/powerhint.xml
+    $(LOCAL_PATH)/powerhint.json:$(TARGET_COPY_OUT_VENDOR)/etc/powerhint.json
 
 # health HAL
 PRODUCT_PACKAGES += \
diff --git a/init.hardware.rc b/init.hardware.rc
index 7486996..571eb08 100644
--- a/init.hardware.rc
+++ b/init.hardware.rc
@@ -385,7 +385,6 @@
     # b/62837579 elabel directory
     mkdir /data/misc/elabel 0700 system system
 
-
 on early-boot
     # wait for devices
     wait_for_prop sys.qcom.devup 1
@@ -549,11 +548,20 @@
     disabled
 
 on property:sys.post_boot.parsed=1
-    start vendor.perfd
+    # Setup permission for powerHAL
+    chown system system /dev/stune/top-app/schedtune.boost
+    chown system system /dev/cpu_dma_latency
+    chown system system /sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/min_freq
+    chown system system /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
+    chown system system /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
+    chown system system /sys/class/devfreq/soc:qcom,gpubw/min_freq
+    chown system system /sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/bw_hwmon/hyst_trigger_count
+    chown system system /sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/bw_hwmon/hist_memory
+    chown system system /sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/bw_hwmon/hyst_length
+    chown system system /sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/min_freq
 
 on property:sys.boot_completed=1
     # Enable power setting and set sys.post_boot.parsed to 1
-    # to start perfd
     start vendor.power_sh
 
     # Enable UFS powersaving
diff --git a/power-libperfmgr/Android.bp b/power-libperfmgr/Android.bp
new file mode 100644
index 0000000..8deca67
--- /dev/null
+++ b/power-libperfmgr/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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_binary {
+    name: "android.hardware.power@1.2-service.wahoo-libperfmgr",
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.power@1.2-service.wahoo-libperfmgr.rc"],
+    srcs: ["service.cpp", "Power.cpp", "InteractionHandler.cpp", "power-helper.c"],
+    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",
+        "libperfmgr",
+    ],
+    proprietary: true,
+}
diff --git a/power-libperfmgr/InteractionHandler.cpp b/power-libperfmgr/InteractionHandler.cpp
new file mode 100644
index 0000000..b8ce3ef
--- /dev/null
+++ b/power-libperfmgr/InteractionHandler.cpp
@@ -0,0 +1,244 @@
+/*
+ * 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_NDEBUG 0
+
+#define LOG_TAG "android.hardware.power@1.2-service.wahoo-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 "InteractionHandler.h"
+
+#define FB_IDLE_PATH "/sys/class/graphics/fb0/idle_state"
+#define MAX_LENGTH 64
+
+#define MSINSEC 1000L
+#define USINMS 1000000L
+
+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();
+}
+
+bool InteractionHandler::Init() {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    if (mState != INTERACTION_STATE_UNINITIALIZED)
+        return true;
+
+    mIdleFd = open(FB_IDLE_PATH, O_RDONLY);
+    if (mIdleFd < 0) {
+        ALOGE("Unable to open idle state path (%d)", errno);
+        return false;
+    }
+
+    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);
+}
+
+long long InteractionHandler::CalcTimespecDiffMs(struct timespec start,
+                                               struct timespec end) {
+    long long 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) {
+        long long 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__, mDurationMs, finalDuration, 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();
+    }
+}
diff --git a/power-libperfmgr/InteractionHandler.h b/power-libperfmgr/InteractionHandler.h
new file mode 100644
index 0000000..893c72f
--- /dev/null
+++ b/power-libperfmgr/InteractionHandler.h
@@ -0,0 +1,71 @@
+/*
+ * 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 INTERACTIONHANDLER_H
+#define INTERACTIONHANDLER_H
+
+#include <condition_variable>
+#include <mutex>
+#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,
+};
+
+struct InteractionHandler {
+    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();
+
+    long long 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 //INTERACTIONHANDLER_H
diff --git a/power-libperfmgr/Power.cpp b/power-libperfmgr/Power.cpp
new file mode 100644
index 0000000..50608d5
--- /dev/null
+++ b/power-libperfmgr/Power.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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.2-service.wahoo-libperfmgr"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <utils/Log.h>
+
+#include "Power.h"
+
+#include "power-helper.h"
+
+/* RPM runs at 19.2Mhz. Divide by 19200 for msec */
+#define RPM_CLK 19200
+
+extern struct stat_pair rpm_stat_map[];
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using ::android::hardware::power::V1_0::Status;
+using ::android::hardware::power::V1_1::PowerStateSubsystem;
+using ::android::hardware::power::V1_1::PowerStateSubsystemSleepState;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+Power::Power() :
+        mHintManager(HintManager::GetFromJSON("/vendor/etc/powerhint.json")),
+        mInteractionHandler(mHintManager),
+        mVRModeOn(false),
+        mSustainedPerfModeOn(false),
+        mEncoderModeOn(false) {
+    mInteractionHandler.Init();
+}
+
+// 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 (!isSupportedGovernor()) {
+        return Void();
+    }
+
+    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::VIDEO_ENCODE:
+            if (mVRModeOn || mSustainedPerfModeOn) {
+                ALOGV("%s: ignoring due to other active perf hints", __func__);
+            } else {
+                if (data) {
+                    // Hint until canceled
+                    mHintManager->DoHint("VIDEO_ENCODE");
+                    ALOGD("VIDEO_ENCODE ON");
+                    mEncoderModeOn = true;
+                } else {
+                    mHintManager->EndHint("VIDEO_ENCODE");
+                    ALOGD("VIDEO_ENCODE OFF");
+                    mEncoderModeOn = false;
+                }
+            }
+            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");
+                    ALOGD("LAUNCH ON");
+                } else {
+                    mHintManager->EndHint("LAUNCH");
+                    ALOGD("LAUNCH OFF");
+                }
+            }
+            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) {
+
+    hidl_vec<PowerStatePlatformSleepState> states;
+    uint64_t stats[MAX_PLATFORM_STATS * MAX_RPM_PARAMS] = {0};
+    uint64_t *values;
+    struct PowerStatePlatformSleepState *state;
+    int ret;
+
+    states.resize(PLATFORM_SLEEP_MODES_COUNT);
+
+    ret = extract_platform_stats(stats);
+    if (ret != 0) {
+        states.resize(0);
+        goto done;
+    }
+
+    /* Update statistics for XO_shutdown */
+    state = &states[RPM_MODE_XO];
+    state->name = "XO_shutdown";
+    values = stats + (RPM_MODE_XO * MAX_RPM_PARAMS);
+
+    state->residencyInMsecSinceBoot = values[1];
+    state->totalTransitions = values[0];
+    state->supportedOnlyInSuspend = false;
+    state->voters.resize(XO_VOTERS);
+    for(size_t i = 0; i < XO_VOTERS; i++) {
+        int voter = static_cast<int>(i + XO_VOTERS_START);
+        state->voters[i].name = rpm_stat_map[voter].label;
+        values = stats + (voter * MAX_RPM_PARAMS);
+        state->voters[i].totalTimeInMsecVotedForSinceBoot = values[0] / RPM_CLK;
+        state->voters[i].totalNumberOfTimesVotedSinceBoot = values[1];
+    }
+
+    /* Update statistics for VMIN state */
+    state = &states[RPM_MODE_VMIN];
+    state->name = "VMIN";
+    values = stats + (RPM_MODE_VMIN * MAX_RPM_PARAMS);
+
+    state->residencyInMsecSinceBoot = values[1];
+    state->totalTransitions = values[0];
+    state->supportedOnlyInSuspend = false;
+    state->voters.resize(VMIN_VOTERS);
+    //Note: No filling of state voters since VMIN_VOTERS = 0
+
+done:
+    _hidl_cb(states, Status::SUCCESS);
+    return Void();
+}
+
+static int get_wlan_low_power_stats(struct PowerStateSubsystem &subsystem) {
+
+    uint64_t stats[WLAN_POWER_PARAMS_COUNT] = {0};
+    struct PowerStateSubsystemSleepState *state;
+    int ret;
+
+    ret = extract_wlan_stats(stats);
+    if (ret)
+        return ret;
+
+    subsystem.name = "wlan";
+    subsystem.states.resize(WLAN_STATES_COUNT);
+
+    /* Update statistics for Active State */
+    state = &subsystem.states[WLAN_STATE_ACTIVE];
+    state->name = "Active";
+    state->residencyInMsecSinceBoot = stats[CUMULATIVE_TOTAL_ON_TIME_MS];
+    state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
+    state->lastEntryTimestampMs = 0; //FIXME need a new value from Qcom
+    state->supportedOnlyInSuspend = false;
+
+    /* Update statistics for Deep-Sleep state */
+    state = &subsystem.states[WLAN_STATE_DEEP_SLEEP];
+    state->name = "Deep-Sleep";
+    state->residencyInMsecSinceBoot = stats[CUMULATIVE_SLEEP_TIME_MS];
+    state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
+    state->lastEntryTimestampMs = stats[LAST_DEEP_SLEEP_ENTER_TSTAMP_MS];
+    state->supportedOnlyInSuspend = false;
+
+    return 0;
+}
+
+// Methods from ::android::hardware::power::V1_1::IPower follow.
+Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
+
+    hidl_vec<PowerStateSubsystem> subsystems;
+    int ret;
+
+    subsystems.resize(SUBSYSTEM_COUNT);
+
+    //We currently have only one Subsystem for WLAN
+    ret = get_wlan_low_power_stats(subsystems[SUBSYSTEM_WLAN]);
+    if (ret != 0)
+        goto done;
+
+    //Add query for other subsystems here
+
+done:
+    _hidl_cb(subsystems, Status::SUCCESS);
+    return Void();
+}
+
+bool Power::isSupportedGovernor() {
+    std::string buf;
+    if (android::base::ReadFileToString("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", &buf)) {
+        buf = android::base::Trim(buf);
+    }
+    // Only support EAS 1.2, legacy EAS
+    if (buf == "schedutil" || buf == "sched") {
+        return true;
+    } else {
+        LOG(ERROR) << "Governor not supported by powerHAL, skipping";
+        return false;
+    }
+}
+
+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 (!isSupportedGovernor()) {
+        return Void();
+    }
+
+    switch(hint) {
+        case PowerHint_1_2::AUDIO_LOW_LATENCY:
+            if (data) {
+                // Hint until canceled
+                mHintManager->DoHint("AUDIO_LOW_LATENCY");
+                ALOGD("AUDIO LOW LATENCY ON");
+            } else {
+                mHintManager->EndHint("AUDIO_LOW_LATENCY");
+                ALOGD("AUDIO LOW LATENCY OFF");
+            }
+            break;
+        case PowerHint_1_2::AUDIO_STREAMING:
+            if (data) {
+                // Hint until canceled
+                mHintManager->DoHint("AUDIO_STREAMING");
+                ALOGD("AUDIO LOW LATENCY ON");
+            } else {
+                mHintManager->EndHint("AUDIO_STREAMING");
+                ALOGD("AUDIO LOW LATENCY OFF");
+            }
+            break;
+        case PowerHint_1_2::CAMERA_LAUNCH:
+            if (data > 0) {
+                mHintManager->DoHint("CAMERA_LAUNCH", std::chrono::milliseconds(data));
+                ALOGD("CAMERA LAUNCH ON: %d MS", data);
+                // boosts 2.5s for launching
+                mHintManager->DoHint("LAUNCH", std::chrono::milliseconds(2500));
+            } else if (data == 0) {
+                mHintManager->EndHint("CAMERA_LAUNCH");
+                ALOGD("CAMERA LAUNCH OFF");
+            } else {
+                ALOGE("CAMERA LAUNCH INVALID DATA: %d", data);
+            }
+            break;
+        case PowerHint_1_2::CAMERA_STREAMING:
+            if (data > 0) {
+                mHintManager->DoHint("CAMERA_STREAMING", std::chrono::milliseconds(data));
+                ALOGD("CAMERA STREAMING ON: %d MS", data);
+            } else if (data == 0) {
+                mHintManager->EndHint("CAMERA_STREAMING");
+                ALOGD("CAMERA STREAMING OFF");
+            } else {
+                ALOGE("CAMERA STREAMING INVALID DATA: %d", data);
+            }
+            break;
+        case PowerHint_1_2::CAMERA_SHOT:
+            if (data > 0) {
+                mHintManager->DoHint("CAMERA_SHOT", std::chrono::milliseconds(data));
+                ALOGD("CAMERA SHOT ON: %d MS", data);
+            } else if (data == 0) {
+                mHintManager->EndHint("CAMERA_SHOT");
+                ALOGD("CAMERA SHOT OFF");
+            } else {
+                ALOGE("CAMERA SHOT INVALID DATA: %d", data);
+            }
+            break;
+        default:
+            return powerHint(static_cast<PowerHint_1_0>(hint), data);
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
diff --git a/power-libperfmgr/Power.h b/power-libperfmgr/Power.h
new file mode 100644
index 0000000..2d84fa5
--- /dev/null
+++ b/power-libperfmgr/Power.h
@@ -0,0 +1,77 @@
+/*
+ * 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 ANDROID_HARDWARE_POWER_V1_2_POWER_H
+#define ANDROID_HARDWARE_POWER_V1_2_POWER_H
+
+#include <atomic>
+
+#include <android/hardware/power/1.2/IPower.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include "InteractionHandler.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_2::IPower;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::InteractionHandler;
+using PowerHint_1_0 = ::android::hardware::power::V1_0::PowerHint;
+using PowerHint_1_2 = ::android::hardware::power::V1_2::PowerHint;
+using ::android::perfmgr::HintManager;
+
+struct Power : public IPower {
+    // 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::hidl::base::V1_0::IBase follow.
+
+ private:
+    std::shared_ptr<HintManager> mHintManager;
+    InteractionHandler mInteractionHandler;
+    static bool isSupportedGovernor();
+    std::atomic<bool> mVRModeOn;
+    std::atomic<bool> mSustainedPerfModeOn;
+    std::atomic<bool> mEncoderModeOn;
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_POWER_V1_2_POWER_H
diff --git a/power-libperfmgr/android.hardware.power@1.2-service.wahoo-libperfmgr.rc b/power-libperfmgr/android.hardware.power@1.2-service.wahoo-libperfmgr.rc
new file mode 100644
index 0000000..65c43b6
--- /dev/null
+++ b/power-libperfmgr/android.hardware.power@1.2-service.wahoo-libperfmgr.rc
@@ -0,0 +1,4 @@
+service vendor.power-hal-1-2 /vendor/bin/hw/android.hardware.power@1.2-service.wahoo-libperfmgr
+    class hal
+    user system
+    group system
diff --git a/power-libperfmgr/power-helper.c b/power-libperfmgr/power-helper.c
new file mode 100644
index 0000000..e355710
--- /dev/null
+++ b/power-libperfmgr/power-helper.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * *    * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_NIDEBUG 0
+#define LOG_TAG "android.hardware.power@1.2-service.wahoo-libperfmgr"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include <log/log.h>
+
+#include "power-helper.h"
+
+#ifndef RPM_SYSTEM_STAT
+#define RPM_SYSTEM_STAT "/d/system_stats"
+#endif
+
+#ifndef WLAN_POWER_STAT
+#define WLAN_POWER_STAT "/d/wlan0/power_stats"
+#endif
+
+#define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
+#define LINE_SIZE 128
+
+const char *rpm_stat_params[MAX_RPM_PARAMS] = {
+    "count",
+    "actual last sleep(msec)",
+};
+
+const char *master_stat_params[MAX_RPM_PARAMS] = {
+    "Accumulated XO duration",
+    "XO Count",
+};
+
+struct stat_pair rpm_stat_map[] = {
+    { RPM_MODE_XO,   "RPM Mode:vlow", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
+    { RPM_MODE_VMIN, "RPM Mode:vmin", rpm_stat_params, ARRAY_SIZE(rpm_stat_params) },
+    { VOTER_APSS,    "APSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
+    { VOTER_MPSS,    "MPSS",    master_stat_params, ARRAY_SIZE(master_stat_params) },
+    { VOTER_ADSP,    "ADSP",    master_stat_params, ARRAY_SIZE(master_stat_params) },
+    { VOTER_SLPI,    "SLPI",    master_stat_params, ARRAY_SIZE(master_stat_params) },
+};
+
+
+const char *wlan_power_stat_params[] = {
+    "cumulative_sleep_time_ms",
+    "cumulative_total_on_time_ms",
+    "deep_sleep_enter_counter",
+    "last_deep_sleep_enter_tstamp_ms"
+};
+
+struct stat_pair wlan_stat_map[] = {
+    { WLAN_POWER_DEBUG_STATS, "POWER DEBUG STATS", wlan_power_stat_params, ARRAY_SIZE(wlan_power_stat_params) },
+};
+
+static int parse_stats(const char **params, size_t params_size,
+                       uint64_t *list, FILE *fp) {
+    ssize_t nread;
+    size_t len = LINE_SIZE;
+    char *line;
+    size_t params_read = 0;
+    size_t i;
+
+    line = malloc(len);
+    if (!line) {
+        ALOGE("%s: no memory to hold line", __func__);
+        return -ENOMEM;
+    }
+
+    while ((params_read < params_size) &&
+        (nread = getline(&line, &len, fp) > 0)) {
+        char *key = line + strspn(line, " \t");
+        char *value = strchr(key, ':');
+        if (!value || (value > (line + len)))
+            continue;
+        *value++ = '\0';
+
+        for (i = 0; i < params_size; i++) {
+            if (!strcmp(key, params[i])) {
+                list[i] = strtoull(value, NULL, 0);
+                params_read++;
+                break;
+            }
+        }
+    }
+    free(line);
+
+    return 0;
+}
+
+
+static int extract_stats(uint64_t *list, char *file,
+                         struct stat_pair *map, size_t map_size) {
+    FILE *fp;
+    ssize_t read;
+    size_t len = LINE_SIZE;
+    char *line;
+    size_t i, stats_read = 0;
+    int ret = 0;
+
+    fp = fopen(file, "re");
+    if (fp == NULL) {
+        ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
+        return -errno;
+    }
+
+    line = malloc(len);
+    if (!line) {
+        ALOGE("%s: no memory to hold line", __func__);
+        fclose(fp);
+        return -ENOMEM;
+    }
+
+    while ((stats_read < map_size) && (read = getline(&line, &len, fp) != -1)) {
+        size_t begin = strspn(line, " \t");
+
+        for (i = 0; i < map_size; i++) {
+            if (!strncmp(line + begin, map[i].label, strlen(map[i].label))) {
+                stats_read++;
+                break;
+            }
+        }
+
+        if (i == map_size)
+            continue;
+
+        ret = parse_stats(map[i].parameters, map[i].num_parameters,
+                          &list[map[i].stat * MAX_RPM_PARAMS], fp);
+        if (ret < 0)
+            break;
+    }
+    free(line);
+    fclose(fp);
+
+    return ret;
+}
+
+int extract_platform_stats(uint64_t *list) {
+    return extract_stats(list, RPM_SYSTEM_STAT, rpm_stat_map, ARRAY_SIZE(rpm_stat_map));
+}
+
+int extract_wlan_stats(uint64_t *list) {
+    return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map));
+}
diff --git a/power-libperfmgr/power-helper.h b/power-libperfmgr/power-helper.h
new file mode 100644
index 0000000..6064646
--- /dev/null
+++ b/power-libperfmgr/power-helper.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * *    * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __POWER_HELPER_H__
+#define __POWER_HELPER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum stats_type {
+    //Platform Stats
+    RPM_MODE_XO = 0,
+    RPM_MODE_VMIN,
+    RPM_MODE_MAX,
+    XO_VOTERS_START = RPM_MODE_MAX,
+    VOTER_APSS = XO_VOTERS_START,
+    VOTER_MPSS,
+    VOTER_ADSP,
+    VOTER_SLPI,
+    MAX_PLATFORM_STATS,
+
+    //WLAN Stats
+    WLAN_POWER_DEBUG_STATS = 0,
+    MAX_WLAN_STATS,
+};
+
+enum subsystem_type {
+    SUBSYSTEM_WLAN = 0,
+
+    //Don't add any lines after this line
+    SUBSYSTEM_COUNT
+};
+
+enum wlan_sleep_states {
+    WLAN_STATE_ACTIVE = 0,
+    WLAN_STATE_DEEP_SLEEP,
+
+    //Don't add any lines after this line
+    WLAN_STATES_COUNT
+};
+
+enum wlan_power_params {
+    CUMULATIVE_SLEEP_TIME_MS = 0,
+    CUMULATIVE_TOTAL_ON_TIME_MS,
+    DEEP_SLEEP_ENTER_COUNTER,
+    LAST_DEEP_SLEEP_ENTER_TSTAMP_MS,
+
+    //Don't add any lines after this line
+    WLAN_POWER_PARAMS_COUNT
+};
+
+
+#define PLATFORM_SLEEP_MODES_COUNT RPM_MODE_MAX
+
+#define MAX_RPM_PARAMS 2
+#define XO_VOTERS (MAX_PLATFORM_STATS - XO_VOTERS_START)
+#define VMIN_VOTERS 0
+
+struct stat_pair {
+    enum stats_type stat;
+    const char *label;
+    const char **parameters;
+    size_t num_parameters;
+};
+
+int extract_platform_stats(uint64_t *list);
+int extract_wlan_stats(uint64_t *list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__POWER_HELPER_H__
diff --git a/power-libperfmgr/service.cpp b/power-libperfmgr/service.cpp
new file mode 100644
index 0000000..77fb139
--- /dev/null
+++ b/power-libperfmgr/service.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.2-service.wahoo-libperfmgr"
+
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Power.h"
+
+using android::sp;
+using android::status_t;
+using android::OK;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::V1_2::IPower;
+using android::hardware::power::V1_2::implementation::Power;
+
+int main() {
+
+    status_t status;
+    android::sp<IPower> service = nullptr;
+
+    ALOGI("Power HAL Service 1.2 for Wahoo is starting.");
+
+    service = new Power();
+    if (service == nullptr) {
+        ALOGE("Can not create an instance of Power HAL Iface, exiting.");
+
+        goto shutdown;
+    }
+
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    status = service->registerAsService();
+    if (status != OK) {
+        ALOGE("Could not register service for Power HAL Iface (%d).", status);
+        goto shutdown;
+    }
+
+    ALOGI("Power Service is ready");
+    joinRpcThreadpool();
+    //Should not pass this line
+
+shutdown:
+    // In normal operation, we don't expect the thread pool to exit
+
+    ALOGE("Power Service is shutting down");
+    return 1;
+}
diff --git a/powerhint.json b/powerhint.json
new file mode 100755
index 0000000..b641df3
--- /dev/null
+++ b/powerhint.json
@@ -0,0 +1,431 @@
+{
+  "Nodes": [
+    {
+      "Name": "CPULittleClusterMinFreq",
+      "Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq",
+      "Values": [
+        "1900800",
+        "1555200",
+        "1512000",
+        "1478400",
+        "1134000",
+        "384000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPULittleClusterMaxFreq",
+      "Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq",
+      "Values": [
+        "1555200",
+        "1478400",
+        "1248000",
+        "1900800"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBigClusterMinFreq",
+      "Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq",
+      "Values": [
+        "2457600",
+        "1574400",
+        "1420800",
+        "1344000",
+        "1132800",
+        "300000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBigClusterMaxFreq",
+      "Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq",
+      "Values": [
+        "1132800",
+        "1267200",
+        "1344000",
+        "1574400",
+        "1958400",
+        "2457600"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUMinFreq",
+      "Path": "/sys/class/kgsl/kgsl-3d0/devfreq/min_freq",
+      "Values": [
+        "515000000",
+        "414000000",
+        "257000000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUMaxFreq",
+      "Path": "/sys/class/kgsl/kgsl-3d0/devfreq/max_freq",
+      "Values": [
+        "342000000",
+        "414000000",
+        "515000000",
+        "710000000"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "GPUBusMinFreq",
+      "Path": "/sys/class/devfreq/soc:qcom,gpubw/min_freq",
+      "Values": [
+        "11863",
+        "7759",
+        "0"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "TASchedtuneBoost",
+      "Path": "/dev/stune/top-app/schedtune.boost",
+      "Values": [
+        "50",
+        "10"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWHystTriggerCount",
+      "Path": "/sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/bw_hwmon/hyst_trigger_count",
+      "Values": [
+        "0",
+        "3"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWHistMemory",
+      "Path": "/sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/bw_hwmon/hist_memory",
+      "Values": [
+        "0",
+        "20"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWHystLength",
+      "Path": "/sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/bw_hwmon/hyst_length",
+      "Values": [
+        "0",
+        "10"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "CPUBWMinFreq",
+      "Path": "/sys/devices/soc/soc:qcom,cpubw/devfreq/soc:qcom,cpubw/min_freq",
+      "Values": [
+        "13763",
+        "5195",
+        "1525",
+        "762"
+      ],
+      "ResetOnInit": true
+    },
+    {
+      "Name": "PMQoSCpuDmaLatency",
+      "Path": "/dev/cpu_dma_latency",
+      "Values": [
+        "44",
+        "100"
+      ],
+      "HoldFd": true
+    }
+  ],
+  "Actions": [
+    {
+      "PowerHint": "VIDEO_ENCODE",
+      "Node": "CPUBigClusterMaxFreq",
+      "ValueIndex": 4,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "CPUBigClusterMaxFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "CPULittleClusterMaxFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "SUSTAINED_PERFORMANCE",
+      "Node": "GPUMaxFreq",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_MODE",
+      "Node": "CPUBigClusterMaxFreq",
+      "ValueIndex": 3,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_MODE",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_MODE",
+      "Node": "CPULittleClusterMaxFreq",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_MODE",
+      "Node": "CPULittleClusterMinFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_MODE",
+      "Node": "GPUMaxFreq",
+      "ValueIndex": 2,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_MODE",
+      "Node": "GPUMinFreq",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_MODE",
+      "Node": "GPUBusMinFreq",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_SUSTAINED_PERFORMANCE",
+      "Node": "CPUBigClusterMaxFreq",
+      "ValueIndex": 2,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_SUSTAINED_PERFORMANCE",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 3,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_SUSTAINED_PERFORMANCE",
+      "Node": "CPULittleClusterMaxFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_SUSTAINED_PERFORMANCE",
+      "Node": "CPULittleClusterMinFreq",
+      "ValueIndex": 3,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_SUSTAINED_PERFORMANCE",
+      "Node": "GPUMaxFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_SUSTAINED_PERFORMANCE",
+      "Node": "GPUMaxFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "VR_SUSTAINED_PERFORMANCE",
+      "Node": "GPUBusMinFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 4,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPULittleClusterMinFreq",
+      "ValueIndex": 4,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "TASchedtuneBoost",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWHystTriggerCount",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWHystLength",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWHistMemory",
+      "ValueIndex": 0,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "INTERACTION",
+      "Node": "CPUBWMinFreq",
+      "ValueIndex": 1,
+      "Duration": 0
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 5000
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPULittleClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 5000
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "PMQoSCpuDmaLatency",
+      "ValueIndex": 0,
+      "Duration": 5000
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWHystTriggerCount",
+      "ValueIndex": 0,
+      "Duration": 5000
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWHystLength",
+      "ValueIndex": 0,
+      "Duration": 5000
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWHistMemory",
+      "ValueIndex": 0,
+      "Duration": 5000
+    },
+    {
+      "PowerHint": "LAUNCH",
+      "Node": "CPUBWMinFreq",
+      "ValueIndex": 0,
+      "Duration": 5000
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "CPULittleClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_LAUNCH",
+      "Node": "PMQoSCpuDmaLatency",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "CPULittleClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_STREAMING",
+      "Node": "PMQoSCpuDmaLatency",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPULittleClusterMinFreq",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "PMQoSCpuDmaLatency",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBWHystTriggerCount",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBWHystLength",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBWHistMemory",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "CAMERA_SHOT",
+      "Node": "CPUBWMinFreq",
+      "ValueIndex": 0,
+      "Duration": 1000
+    },
+    {
+      "PowerHint": "AUDIO_STREAMING",
+      "Node": "CPUBigClusterMinFreq",
+      "ValueIndex": 2,
+      "Duration": 2000
+    },
+    {
+      "PowerHint": "AUDIO_STREAMING",
+      "Node": "PMQoSCpuDmaLatency",
+      "ValueIndex": 0,
+      "Duration": 2000
+    },
+    {
+      "PowerHint": "AUDIO_LOW_LATENCY",
+      "Node": "PMQoSCpuDmaLatency",
+      "ValueIndex": 0,
+      "Duration": 0
+    }
+  ]
+}
diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts
index 2af2d30..1183932 100644
--- a/sepolicy/vendor/file_contexts
+++ b/sepolicy/vendor/file_contexts
@@ -169,6 +169,7 @@
 /vendor/bin/oemlock-bridge      u:object_r:hal_bootctl_default_exec:s0
 /vendor/bin/hw/android\.hardware\.usb@1\.1-service.wahoo             u:object_r:hal_usb_default_exec:s0
 /vendor/bin/hw/android\.hardware\.power@1\.2-service.wahoo           u:object_r:hal_power_default_exec:s0
+/vendor/bin/hw/android\.hardware\.power@1\.2-service.wahoo-libperfmgr u:object_r:hal_power_default_exec:s0
 /vendor/bin/hw/android\.hardware\.thermal@1\.0-service.wahoo         u:object_r:hal_thermal_default_exec:s0
 /vendor/bin/chre                u:object_r:chre_exec:s0
 /vendor/bin/time_daemon         u:object_r:time_daemon_exec:s0
diff --git a/sepolicy/vendor/hal_camera.te b/sepolicy/vendor/hal_camera.te
index 38edfc3..587e078 100644
--- a/sepolicy/vendor/hal_camera.te
+++ b/sepolicy/vendor/hal_camera.te
@@ -1,7 +1,7 @@
 # communicate with perfd
-allow hal_camera perfd:unix_stream_socket connectto;
-allow hal_camera perfd_socket:sock_file write;
-allow hal_camera perfd_socket:sock_file w_file_perms;
+dontaudit hal_camera perfd:unix_stream_socket connectto;
+dontaudit hal_camera perfd_socket:sock_file write;
+dontaudit hal_camera perfd_socket:sock_file w_file_perms;
 
 allow hal_camera self:capability sys_nice;
 
diff --git a/sepolicy/vendor/hal_power_default.te b/sepolicy/vendor/hal_power_default.te
index b588634..3794e32 100644
--- a/sepolicy/vendor/hal_power_default.te
+++ b/sepolicy/vendor/hal_power_default.te
@@ -1,6 +1,3 @@
-allow hal_power_default perfd:unix_stream_socket connectto;
-allow hal_power_default perfd_socket:sock_file write;
-
 allow hal_power_default sysfs_graphics:dir search;
 allow hal_power_default sysfs_graphics:file r_file_perms;
 
@@ -8,3 +5,9 @@
 
 allow hal_power_default debugfs_wlan:dir r_dir_perms;
 allow hal_power_default debugfs_wlan:file r_file_perms;
+
+# To do powerhint on nodes defined in powerhint.json
+allow hal_power_default sysfs_msm_subsys:dir search;
+allow hal_power_default sysfs_msm_subsys:file w_file_perms;
+allow hal_power_default sysfs_devices_system_cpu:file w_file_perms;
+allow hal_power_default latency_device:chr_file w_file_perms;
diff --git a/sepolicy/vendor/perfd.te b/sepolicy/vendor/perfd.te
index fa99d15..950e1d6 100644
--- a/sepolicy/vendor/perfd.te
+++ b/sepolicy/vendor/perfd.te
@@ -2,31 +2,3 @@
 type perfd_exec, exec_type, vendor_file_type, file_type;
 
 init_daemon_domain(perfd)
-
-r_dir_file(perfd, sysfs_msm_subsys)
-
-# perfd uses kill(pid, 0) to determine if a process exists.
-# Determining if a process exists does not require the kill capability
-# since a permission denied indicates the process exists.
-dontaudit perfd self:capability kill;
-
-allow perfd mediacodec:process signull;
-allow perfd hal_power_default:process signull;
-
-allow perfd cgroup:file r_file_perms;
-allow perfd post_boot_prop:file r_file_perms;
-
-allow perfd proc:file rw_file_perms;
-allow perfd sysfs_clkscale:file r_file_perms;
-allow perfd sysfs_graphics:dir search;
-allow perfd sysfs_graphics:file r_file_perms;
-allow perfd sysfs_soc:dir search;
-allow perfd sysfs_soc:file r_file_perms;
-allow perfd sysfs_graphics:dir search;
-allow perfd sysfs_graphics:file r_file_perms;
-allow perfd sysfs_msm_subsys:file w_file_perms;
-allow perfd sysfs_devices_system_cpu:file w_file_perms;
-
-allow perfd perfd_socket:sock_file write;
-
-allow perfd latency_device:chr_file w_file_perms;