RM6785: power-libperfmgr: Import power HAL AIDL implementation

Author: Bruno Martins <bgcngm@gmail.com>
Date:   Sat Apr 17 17:01:20 2021 +0100

    power-libperfmgr: Import power HAL AIDL implementation

    Change-Id: I7cd1ea241920bc76756df12a2e46e5a33f48b797

Author: Wei Wang <wvw@google.com>
Date:   Fri Mar 13 11:34:11 2020 -0700

    power-libperfmgr: Hook with display handler

    Bug: 147840817
    Test: boot and check power hint

Author: Wei Wang <wvw@google.com>
Date:   Fri Mar 20 12:21:12 2020 -0700

    power-libperfmgr: add aidl extension server

    Bug: 151896829
    Test: boot flame

Author: Wei Wang <wvw@google.com>
Date:   Fri Mar 20 22:11:48 2020 -0700

    power-libperfmgr: allow powerhint calls as soon as service starts

    Bug: 147840817
    Test: boot

Author: Wei Wang <wvw@google.com>
Date:   Mon Mar 30 18:28:45 2020 -0700

    power-libperfmgr: rename namespace for Pixel power HAL

    Bug: 152811907
    Test: Build

Author: Kyle Lin <kylelin@google.com>
Date:   Mon Aug 10 18:12:41 2020 +0800

    libperfmgr.rc: let perfmgr can change dex2oat priorities

    Because perfmgr is a vendor process, it cannot adjust system priority
    directly.

    Bug: 162791243

    Test: build and using emul temp/running burn8 to verify it

Author: Kyle Lin <kylelin@google.com>
Date:   Wed Aug 12 16:00:15 2020 +0800

    libperfmgr.rc: let power hal start early

    Bug: 162791243
    Bug: 72471476
    Test: build and using emul temp/running burn8 to verify it

Author: Jesse Chan <jc@lineageos.org>
Date:   Mon Jun 29 12:26:29 2020 +0800

    power-libperfmgr: remove Google-specific VR and camera hints

Author: Wei Wang <wvw@google.com>
Date:   Wed Oct 21 12:15:30 2020 -0700

    Power: add support for devices without display idle signals

    To workaround b/141025174, adding support for devices without display
    idle signals. Also added a property to override idle display function.

    Besides the idle signal support, this CL also makes touch boost duration
    tunable through several new vendor properties. It also named display
    idle monitor thread and cleans out the obsolete HIDL Power HAL
    implementation.

    Bug: 168080943
    Bug: 169065024
    Bug: 171494137
    Test: Boot and trace

Author: Wei Wang <wvw@google.com>
Date:   Thu Oct 22 16:21:39 2020 -0700

    Power: advertise power headers are deprecated

    Test: Build
    Bug: 169065024
    Signed-off-by: Wei Wang <wvw@google.com>

Author: Wei Wang <wvw@google.com>
Date:   Fri Nov 13 10:59:00 2020 -0800

    power: add a property for config file

    Test: build
    Bug: 173222103
    Signed-off-by: Wei Wang <wvw@google.com>

Author: Jeongik Cha <jeongik@google.com>
Date:   Thu Jan 28 00:49:48 2021 +0900

    Specify version for aidl_interface explicitly

    Bug: 150578172
    Test: m

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Mon Jan 25 01:20:38 2021 +0800

    power: add PowerHintSession for ADPF implementation

    Adapted from PoC from ag/13100800

    Added more ATRACE for further tuning and debug

    Test: APPPID=$(adb shell pidof com.prefabulated.touchlatency); watch -n
          1 adb shell grep uclamp /proc/${APPPID}/sched
    Test: atest VtsHalPowerTargetTest
    Bug: 177492680

    Signed-off-by: Wei Wang <wvw@google.com>

Author: Wei Wang <wvw@google.com>
Date:   Wed Apr 14 10:21:50 2021 -0700

    power: reduce log spam and refine trace title

    Add bunch of TODO for team as well.

    Test: build
    Bug: 177492680
    Bug: 185368789
    Signed-off-by: Wei Wang <wvw@google.com>

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Wed May 5 11:17:41 2021 +0800

    ADPF: use PID algorithm to control cpu resource

    The patch includes:
    1. Move from folder adpf to aidl.
    2. Add PowerSessionManager class to maintain hint status.
       And PowerHintMointor looper thread for monitoring or updating
       PowerHintSession status.
    3. Use PID algorithm to replace the step-wise alogrithm for cpu resource
       control.

    Test: build, boot to home, trace analysis
    Bug: 177493042

Author: Wei Wang <wvw@google.com>
Date:   Mon Jun 14 22:03:10 2021 -0700

    Fix objects that are derived from refbase

    Fixes: ag/14313466
    Bug: 177493042
    Bug: 191163855
    Test: Build

    Signed-off-by: Wei Wang <wvw@google.com>

Author: Wei Wang <wvw@google.com>
Date:   Wed Jun 16 21:20:44 2021 -0700

    power-libperfmgr: improve adpf logic

    Cache active state and reduce log spam
    Add value tracing into libperfmgr
    Use adaptive stale timeout based on rate limit

    Bug: 191331719
    Bug: 191296994
    Bug: 177493042
    Test: boot
    Signed-off-by: Wei Wang <wvw@google.com>

Author: Wei Wang <wvw@google.com>
Date:   Thu Jun 17 21:32:18 2021 -0700

    Adpf: honor window setting for P,D caculation

    Also change default window setting to 0

    Bug: 191409203
    Test: Build
    Signed-off-by: Wei Wang <wvw@google.com>

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Mon Jun 21 00:22:47 2021 +0800

    adpf: clean up ADPF trace points

    clean up ADPF trace points and use vendor.powerhal.adpf.uclamp.boost_cap
    instead of vendor.powerhal.adpf.uclamp.cap_ratio.

    Bug: 191551452
    Test: build

Author: Wei Wang <wvw@google.com>
Date:   Wed Jun 23 15:58:56 2021 -0700

    Add PID tunables for sample window

    Bug: 191480755
    Test: Build
    Signed-off-by: Wei Wang <wvw@google.com>

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Sun Jun 27 01:39:31 2021 +0800

    Adpf: set uclamp when session is created

    When seesion is created, set uclamp to boost CPU for top-app.

    Bug: 192143316
    Test: Build and run UiBenchSlowNestedRecyclerViewInitialFlingMicrobenchmark test

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Wed Jul 7 12:00:43 2021 +0800

    ADPF: fix abnormal high uclamp

    "GPU completion" task inherits a high uclamp value from RenderThread.
    But it's not in the ADPF thread list, so it remains a high uclamp value.
    Use SetTaskProfiles("ResetUclampGrp") and
    SetTaskProfiles("NoResetUclampGrp") to manage the uclamp_fork_reset for
    tasks.

    Bug: 191973176
    Bug: 192149875
    Test: vendor/google_testing/pts/tests/common/utils/perf/run_pts/jank_test.sh
    Test: adb shell cat /proc/vendor_sched/dump_task

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Thu Jul 29 23:58:22 2021 +0800

    ADPF: avoid to call close() twice

    To get rid of error logs, avoid to call close() twice.

    07-29 17:20:35.341 E powerhal-libperfmgr: Unexpected Error! Failed to
    look up tid:2585 in TidRefCountMap
    07-29 17:20:35.341 E powerhal-libperfmgr: Unexpected Error! Failed to
    look up tid:2586 in TidRefCountMap
    07-29 17:20:35.341 E powerhal-libperfmgr: Unexpected Error! Failed to
    look up tid:2031 in TidRefCountMap
    07-29 17:20:35.341 E powerhal-libperfmgr: Unexpected Error! Failed to
    look up tid:2585 in TidRefCountMap

    Bug: 194775170
    Test: build and check log.

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Tue Jul 27 10:45:07 2021 +0800

    ADPF: fix no boost due to the big negative ILowLimit

    Tuning the PID control loop as the below:
    ILowLimit: -512 -> -120
    kPOver: 2->5
    kPunder: 2->3
    kDOver: 1->5
    kDUnder: 0->0

    Bug: 193165816
    Test: cuj/youtuble, cuj/facebook, PtsUiBench

Author: Jiyong Park <jiyong@google.com>
Date:   Mon Aug 9 09:01:16 2021 +0900

    power-libperfmgr: Remove ndk_platform backend. Use the ndk backend.

    The ndk_platform backend will soon be deprecated because the ndk backend
    can serve the same purpose. This is to eliminate the confusion about
    having two variants (ndk and ndk_platform) for the same ndk backend.

    Bug: 161456198
    Test: m

Change-Id: I8323fadd841777537f3f28d5605bc3420ed89080

Author: Wei Wang <wvw@google.com>
Date:   Fri Sep 17 15:30:09 2021 -0700

    power: move trace point to libperfmgr.

    Test: systrace
    Bug: 199776250
    Change-Id: I9bb4d5a50faa93e7bc638ef723bdc2662fb63b24

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Wed Sep 8 16:37:34 2021 +0800

    power: ADPF: limit uclamp high/low values and use I as boost base

    1. set uclamp.min high to 384 (from 512)
    2. set uclamp.min low to 2 (from 0)
    3. set kPo to 2 (from 5)
    4. set kPu to 1 (from 3)
    5. instead of the previous boost value, use I Error-Integral as the base
       of boost value.
    6. add more traces (wakeup, overtime)

    Bug: 198708191
    Bug: 197586898
    Bug: 197540375
    Test: build and check trace
          adb shell perfetto -o \
          /data/misc/perfetto-traces/trace_file.perfetto-trace -t 20s sched \
          freq idle am wm gfx view power hal
    Change-Id: I35484322a84c2ab19f3024cf6634c1818ba570b0

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Mon Oct 18 10:02:28 2021 +0800

    power: ADPF: fix stale trace status

    Bug: 196192645
    Test: Manual
    Change-Id: Ibdbb8f47a16032ce3249aa667fa0c11e7869748f

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Fri Feb 11 01:35:47 2022 +0800

    power: Add a debug property for switching powerhint.json path

    Add a bool property `vendor.powerhal.config.debug`.
    Power HAL would use `/data/vendor/etc/powerhint.json` when vendor.powerhal.config.debug = true.

    Bug: 218872105
    Bug: 206061061
    Test: adb wait-for-device root; adb shell mkdir -p /data/vendor/etc/;
          adb push powerhint_mod.json /data/vendor/etc/powerhint.json
    Test: adb shell setprop vendor.powerhal.config.debug true && \
          adb shell getprop vendor.powerhal.config.debug && \
          adb shell stop vendor.power-hal-aidl && \
          adb shell start vendor.power-hal-aidl && adb shell stop && adb shell start
    Test: adb pull /data/local.prop ; vim local.prop
          + vendor.powerhal.config.debug=true
    Test: adb wait-for-device root && adb shell perfetto -o \
          /data/misc/perfetto-traces/trace_file.perfetto-trace -t 20s sched freq \
          idle am wm gfx view power hal && \
          adb pull /data/misc/perfetto-traces/trace_file.perfetto-trace trace_profile_debug.pftrace
    Change-Id: Ibaf5df280b989a8268efce1e3ab9a3f1e5510800

Author: Wei Wang <wvw@google.com>
Date:   Tue Feb 15 21:49:11 2022 -0800

    power: Add global debug property for override config path properly

    An init trigger would restart powerhal as early as the property was
    loaded and it is hopefully early than any clients would try to connect.

    Also remove the obsolete restart hook with audio.

    Bug: 218872105
    Test: boot
    Signed-off-by: Wei Wang <wvw@google.com>
    Change-Id: Ib55897f65709a963016b729f213718aae5af8e8c

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Wed Mar 30 14:43:21 2022 +0800

    power: Fix race condition between Looper and destructor

    1. Clean all messages before add new.
    2. Insteading of using `this`, use the unique mStaleHandler sp so Looper
       can hold the sp to keep the instance alive until the last message
       done.

    Test: Manual Test
    Bug: 219965773
    Change-Id: Ic039146f0b966c1f27d86b121d4b72b75ff360e5

Author: Wei Wang <wvw@google.com>
Date:   Wed Apr 6 10:26:33 2022 -0700

    power: PowerHintSession: do not update PID controller when target changes

    There is no history kept in powerhint session, so let us just keep what
    we have in the PID controller and let new samples settle.

    Bug: 227003278
    Test: Build
    Change-Id: Ia8b9a0be288389ec36ac35c668aca013d470c257

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Sat Feb 12 01:05:23 2022 +0800

    power: Make HintManager a singleton class

    HintManager is unique and widely used in many different components.
    This is for making it easiler to be reloaded for debugging.

    Bug: 172285365
    Test: adb push \
          out/target/product/raven/data/nativetest64/libperfmgr_test/libperfmgr_test \
          /data/nativetest64/libperfmgr_test/libperfmgr_test && \
          adb shell /data/nativetest64/libperfmgr_test/libperfmgr_test
    Change-Id: I3affdfe780073ebbc50fac7bfbdd1530ee9dc8c2

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Tue Nov 9 22:44:46 2021 +0800

    power: ADPF: make uclamp.min stable

    Considering the previous uclamp.min value is the base of PID output.
    Instead of:
      `next_min = std::min(sUclampMinHighLimit, output);`
    We should use:
      `next_min = std::min(sUclampMinHighLimit, current_min + output);`

    When session status entered stale state, set the uclamp to 0, but keep
    the current_min. That would be helpful for boosting the heavy workload
    of the first few frames.

    Bug: 204444691
    Test: build && manual test

    Change-Id: Idb19e2bfd8e9522fae5fd452b1fcc58786e96e65

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Tue Oct 26 17:48:06 2021 +0800

    power: ADPF: Use Adpf Profile for PID tunnables

    1. Use Adpf Profile to replace system-property-based PID tunnables.
    2. Add a tunable for switch PID on/off
    3. Switch Adpf Profile by hint name (ex: REFRESH_120FPS)

    Bug: 202158746
    Bug: 204444691
    Bug: 206061061
    Test: Build
    Change-Id: Ia673a6bf64d40128ca1797d1e26fe564b3b35ff1

Author: Jimmy Shiu <jimmyshiu@google.com>
Date:   Mon Jan 17 21:02:41 2022 +0800

    power: ADPF: add Early Hint feature

    Add Early Hint feature and integrate with Stale Timer

    Bug: 198379880
    Test: build and manual test

    Change-Id: I17009ee5b9ff922a79ccf5cb68be5b959038267d

Author: Wei Wang <wvw@google.com>
Date:   Wed Apr 20 15:22:12 2022 -0700

    power: Add minimal binder thread prio as -20 to match process prio

    Bug: 227811781
    Test: Build
    Change-Id: I94670429ede032703661ee8eb8b1ea6456f5cbd5
    Signed-off-by: Wei Wang <wvw@google.com>

Author: jimmyshiu <jimmyshiu@google.com>
Date:   Mon Apr 25 08:46:49 2022 +0000

    power: ADPF: log clean up

    Remove ALOGD logs.

    Bug: 230205812
    Test: adb shell logcat -b all | grep libperf
    Change-Id: I4125afec526b76e3905e75c22fc2bfb555810fa8

Author: Matt Buckley <mattbuckley@google.com>
Date:   Fri Apr 29 21:05:38 2022 +0000

    power: Ignore system hint sessions for universal boost

    Currently PowerHAL does not distinguish between system processes and
    apps when deciding whether to apply universal boost. This patch
    distinguishes system sessions and app sessions and ignores system ones,
    making the disabling of universal boost dependent on the presence of app
    hint sessions.

    Bug: b/230511824
    Test: manual
    Change-Id: I08dea29b3a45f2ba69ed99a9f188fa83ba143423

Author: Wei Wang <wvw@google.com>
Date:   Thu May 12 09:54:25 2022 -0700

    power: PowerHAL: remove UclampMinGranularity

    This is causing session update skipped and stuck.

    Bug: 232336917
    Test: /data/nativetest64/libperfmgr_test/libperfmgr_test
    Signed-off-by: Wei Wang <wvw@google.com>
    Change-Id: I8928b6f6a60dcf8d21e60228a74d3aa0ab792eff

Author: jimmyshiu <jimmyshiu@google.com>
Date:   Thu May 19 06:43:55 2022 +0000

    power: ADPF: uclamp.min integration

    Integrate the uclamp.min across sessions.
    Add UClampMininit as the display update boost

    Bug: 232313238
    Test: Manual test
    Change-Id: I601f407b0b5383a1e39eac448d45cbaaeb7788fb

Author: jimmyshiu <jimmyshiu@google.com>
Date:   Thu Apr 21 17:39:51 2022 +0000

    power: ADPF: dump ADPF session info

    Dump current ADPF profile and ADPF session list into bugreport.

    Bug: 204444691
    Test: adb root && adb shell dumpsys android.hardware.power.IPower/default
    Test: gpaste/6469309887938560
    Change-Id: I17c0d615051f5e51c2e1fe99d17c402f9a65679a

Author: Will McVicker <willmcvicker@google.com>
Date:   Fri Jun 3 14:54:29 2022 -0700

    power: Fix race between closing a session and receiving a boost

    We need to be holding the session lock when we dereference mDescriptor
    since mDescriptor is destroyed when the session is closed. This patch
    takes the session lock and verifies if it's still open during wakeup.

    Test: vts run -m VtsHalGraphicsComposerV2_4TargetTest
    Bug: 232992641
    Change-Id: I4000a85bf2932cfdcddd3006d671a3c91ed32c48

Author: jimmyshiu <jimmyshiu@google.com>
Date:   Thu Jun 2 09:30:18 2022 +0000

    power: Fix uclamp_min stuck at high freq

    Separate Stale and EarlyBoost handlers and refine the code.

    Test: adb shell dumpsys android.hardware.power.IPower/default
    Test: Manual
    Bug: 232992641

    Change-Id: I81a4fd96fb7311ae5bbb7cbabe72378c9cad4aa3

Author: jimmyshiu <jimmyshiu@google.com>
Date:   Fri Jun 10 10:14:56 2022 +0000

    power: ADPF: Fix updateHintBoost blocks the binder thread

    post the task into a looper thread.

    Bug: 232992641
    Test: Manually playing UIBench -> Transitions -> ActivityTransition
    Change-Id: Ibd241834f904b4c87a51363e766e110d2818d496

Change-Id: Ifd21d00c68ac3a07128970811f624efb3483d4c8

Author: Wei Wang <wvw@google.com>
Date:   Sat Aug 6 00:31:07 2022 -0700

    ADPF: extend non-stale session timer in wakeup

    For DISPLAY_UPDATE_IMMINENT wakeup signal, non-stale
    session's timer should be also extended. This resolves
    the performance issue caused those sessions to go stale    
    prematurely.

    Bug: 241621485
    Test: Build
    Signed-off-by: Wei Wang <wvw@google.com>
    Change-Id: I06330e064060248bb556ae35e0cb8fd302cef231
    (cherry picked from commit 986c81e89ba5bb0537429a631a4c93caf3dc846e)
    Merged-In: I06330e064060248bb556ae35e0cb8fd302cef231

Change-Id: I71b1efeb1f28a361ed015bfe9582632d94bd89e7
diff --git a/Android.bp b/Android.bp
index 9515b25..e69df8d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,2 +1,6 @@
 soong_namespace {
+    imports: [
+        "hardware/google/interfaces",
+        "hardware/google/pixel",
+    ],
 }
diff --git a/aidl/power-libperfmgr/Android.bp b/aidl/power-libperfmgr/Android.bp
new file mode 100644
index 0000000..6200471
--- /dev/null
+++ b/aidl/power-libperfmgr/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2021 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.
+//
+
+cc_binary {
+    name: "android.hardware.power-service.RM6785-libperfmgr",
+
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "android.hardware.power-V2-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libdl",
+        "liblog",
+        "libperfmgr",
+        "libprocessgroup",
+        "libutils",
+        "pixel-power-ext-V1-ndk",
+    ],
+
+    srcs: [
+        "service.cpp",
+        "InteractionHandler.cpp",
+        "Power.cpp",
+        "PowerExt.cpp",
+        "PowerHintSession.cpp",
+        "PowerSessionManager.cpp",
+    ],
+
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+    ],
+
+    init_rc: ["android.hardware.power-service.RM6785-libperfmgr.rc"],
+
+    vendor: true,
+    vintf_fragments: ["android.hardware.power-service.RM6785.xml"],
+
+}
diff --git a/aidl/power-libperfmgr/InteractionHandler.cpp b/aidl/power-libperfmgr/InteractionHandler.cpp
new file mode 100644
index 0000000..a9f908b
--- /dev/null
+++ b/aidl/power-libperfmgr/InteractionHandler.cpp
@@ -0,0 +1,283 @@
+/*
+ * 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 "powerhal-libperfmgr"
+
+#include "InteractionHandler.h"
+
+#include <android-base/properties.h>
+#include <fcntl.h>
+#include <perfmgr/HintManager.h>
+#include <poll.h>
+#include <sys/eventfd.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <array>
+#include <memory>
+
+#define MAX_LENGTH 64
+
+#define MSINSEC 1000L
+#define NSINMS 1000000L
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+namespace {
+
+static const bool kDisplayIdleSupport =
+        ::android::base::GetBoolProperty("vendor.powerhal.disp.idle_support", true);
+static const std::array<const char *, 2> kDispIdlePath = {"/sys/class/drm/card0/device/idle_state",
+                                                          "/sys/class/graphics/fb0/idle_state"};
+static const uint32_t kWaitMs =
+        ::android::base::GetUintProperty("vendor.powerhal.disp.idle_wait", /*default*/ 100U);
+static const uint32_t kMinDurationMs =
+        ::android::base::GetUintProperty("vendor.powerhal.interaction.min", /*default*/ 1400U);
+static const uint32_t kMaxDurationMs =
+        ::android::base::GetUintProperty("vendor.powerhal.interaction.max", /*default*/ 5650U);
+static const uint32_t kDurationOffsetMs =
+        ::android::base::GetUintProperty("vendor.powerhal.interaction.offset", /*default*/ 650U);
+
+static size_t CalcTimespecDiffMs(struct timespec start, struct timespec end) {
+    size_t diff_in_ms = 0;
+    diff_in_ms += (end.tv_sec - start.tv_sec) * MSINSEC;
+    diff_in_ms += (end.tv_nsec - start.tv_nsec) / NSINMS;
+    return diff_in_ms;
+}
+
+static int FbIdleOpen(void) {
+    int fd;
+    for (const auto &path : kDispIdlePath) {
+        fd = open(path, O_RDONLY);
+        if (fd >= 0)
+            return fd;
+    }
+    ALOGE("Unable to open fb idle state path (%d)", errno);
+    return -1;
+}
+
+}  // namespace
+
+using ::android::perfmgr::HintManager;
+
+InteractionHandler::InteractionHandler()
+    : mState(INTERACTION_STATE_UNINITIALIZED), mDurationMs(0) {}
+
+InteractionHandler::~InteractionHandler() {
+    Exit();
+}
+
+bool InteractionHandler::Init() {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    if (mState != INTERACTION_STATE_UNINITIALIZED)
+        return true;
+
+    int fd = FbIdleOpen();
+    if (fd < 0)
+        return false;
+    mIdleFd = fd;
+
+    mEventFd = eventfd(0, EFD_NONBLOCK);
+    if (mEventFd < 0) {
+        ALOGE("Unable to create event fd (%d)", errno);
+        close(mIdleFd);
+        return false;
+    }
+
+    mState = INTERACTION_STATE_IDLE;
+    mThread = std::unique_ptr<std::thread>(new std::thread(&InteractionHandler::Routine, this));
+
+    return true;
+}
+
+void InteractionHandler::Exit() {
+    std::unique_lock<std::mutex> lk(mLock);
+    if (mState == INTERACTION_STATE_UNINITIALIZED)
+        return;
+
+    AbortWaitLocked();
+    mState = INTERACTION_STATE_UNINITIALIZED;
+    lk.unlock();
+
+    mCond.notify_all();
+    mThread->join();
+
+    close(mEventFd);
+    close(mIdleFd);
+}
+
+void InteractionHandler::PerfLock() {
+    ALOGV("%s: acquiring perf lock", __func__);
+    if (!HintManager::GetInstance()->DoHint("INTERACTION")) {
+        ALOGE("%s: do hint INTERACTION failed", __func__);
+    }
+}
+
+void InteractionHandler::PerfRel() {
+    ALOGV("%s: releasing perf lock", __func__);
+    if (!HintManager::GetInstance()->EndHint("INTERACTION")) {
+        ALOGE("%s: end hint INTERACTION failed", __func__);
+    }
+}
+
+void InteractionHandler::Acquire(int32_t duration) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lk(mLock);
+
+    int inputDuration = duration + kDurationOffsetMs;
+    int finalDuration;
+    if (inputDuration > kMaxDurationMs)
+        finalDuration = kMaxDurationMs;
+    else if (inputDuration > kMinDurationMs)
+        finalDuration = inputDuration;
+    else
+        finalDuration = kMinDurationMs;
+
+    // Fallback to do boost directly
+    // 1) override property is set OR
+    // 2) InteractionHandler not initialized
+    if (!kDisplayIdleSupport || mState == INTERACTION_STATE_UNINITIALIZED) {
+        HintManager::GetInstance()->DoHint("INTERACTION", std::chrono::milliseconds(finalDuration));
+        return;
+    }
+
+    struct timespec cur_timespec;
+    clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
+    if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
+        size_t elapsed_time = CalcTimespecDiffMs(mLastTimespec, cur_timespec);
+        // don't hint if previous hint's duration covers this hint's duration
+        if (elapsed_time <= (mDurationMs - finalDuration)) {
+            ALOGV("%s: Previous duration (%d) cover this (%d) elapsed: %lld", __func__,
+                  static_cast<int>(mDurationMs), static_cast<int>(finalDuration),
+                  static_cast<long long>(elapsed_time));
+            return;
+        }
+    }
+    mLastTimespec = cur_timespec;
+    mDurationMs = finalDuration;
+
+    ALOGV("%s: input: %d final duration: %d", __func__, duration, finalDuration);
+
+    if (mState == INTERACTION_STATE_WAITING)
+        AbortWaitLocked();
+    else if (mState == INTERACTION_STATE_IDLE)
+        PerfLock();
+
+    mState = INTERACTION_STATE_INTERACTION;
+    mCond.notify_one();
+}
+
+void InteractionHandler::Release() {
+    std::lock_guard<std::mutex> lk(mLock);
+    if (mState == INTERACTION_STATE_WAITING) {
+        ATRACE_CALL();
+        PerfRel();
+        mState = INTERACTION_STATE_IDLE;
+    } else {
+        // clear any wait aborts pending in event fd
+        uint64_t val;
+        ssize_t ret = read(mEventFd, &val, sizeof(val));
+
+        ALOGW_IF(ret < 0, "%s: failed to clear eventfd (%zd, %d)", __func__, ret, errno);
+    }
+}
+
+// should be called while locked
+void InteractionHandler::AbortWaitLocked() {
+    uint64_t val = 1;
+    ssize_t ret = write(mEventFd, &val, sizeof(val));
+    if (ret != sizeof(val))
+        ALOGW("Unable to write to event fd (%zd)", ret);
+}
+
+void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) {
+    char data[MAX_LENGTH];
+    ssize_t ret;
+    struct pollfd pfd[2];
+
+    ATRACE_CALL();
+
+    ALOGV("%s: wait:%d timeout:%d", __func__, wait_ms, timeout_ms);
+
+    pfd[0].fd = mEventFd;
+    pfd[0].events = POLLIN;
+    pfd[1].fd = mIdleFd;
+    pfd[1].events = POLLPRI | POLLERR;
+
+    ret = poll(pfd, 1, wait_ms);
+    if (ret > 0) {
+        ALOGV("%s: wait aborted", __func__);
+        return;
+    } else if (ret < 0) {
+        ALOGE("%s: error in poll while waiting", __func__);
+        return;
+    }
+
+    ret = pread(mIdleFd, data, sizeof(data), 0);
+    if (!ret) {
+        ALOGE("%s: Unexpected EOF!", __func__);
+        return;
+    }
+
+    if (!strncmp(data, "idle", 4)) {
+        ALOGV("%s: already idle", __func__);
+        return;
+    }
+
+    ret = poll(pfd, 2, timeout_ms);
+    if (ret < 0)
+        ALOGE("%s: Error on waiting for idle (%zd)", __func__, ret);
+    else if (ret == 0)
+        ALOGV("%s: timed out waiting for idle", __func__);
+    else if (pfd[0].revents)
+        ALOGV("%s: wait for idle aborted", __func__);
+    else if (pfd[1].revents)
+        ALOGV("%s: idle detected", __func__);
+}
+
+void InteractionHandler::Routine() {
+    pthread_setname_np(pthread_self(), "DispIdle");
+    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(kWaitMs, mDurationMs);
+        Release();
+    }
+}
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/InteractionHandler.h b/aidl/power-libperfmgr/InteractionHandler.h
new file mode 100644
index 0000000..c88f7d4
--- /dev/null
+++ b/aidl/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.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+enum InteractionState {
+    INTERACTION_STATE_UNINITIALIZED,
+    INTERACTION_STATE_IDLE,
+    INTERACTION_STATE_INTERACTION,
+    INTERACTION_STATE_WAITING,
+};
+
+class InteractionHandler {
+  public:
+    InteractionHandler();
+    ~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();
+
+    enum InteractionState mState;
+    int mIdleFd;
+    int mEventFd;
+    int32_t mDurationMs;
+    struct timespec mLastTimespec;
+    std::unique_ptr<std::thread> mThread;
+    std::mutex mLock;
+    std::condition_variable mCond;
+};
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/Power.cpp b/aidl/power-libperfmgr/Power.cpp
new file mode 100644
index 0000000..b2f7a92
--- /dev/null
+++ b/aidl/power-libperfmgr/Power.cpp
@@ -0,0 +1,227 @@
+/*
+ * 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 "powerhal-libperfmgr"
+
+#include "Power.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <perfmgr/HintManager.h>
+#include <utils/Log.h>
+
+#include <mutex>
+
+#include "PowerHintSession.h"
+#include "PowerSessionManager.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::aidl::google::hardware::power::impl::pixel::PowerHintSession;
+using ::android::perfmgr::HintManager;
+
+constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
+constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
+constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
+
+Power::Power()
+    : mInteractionHandler(nullptr),
+      mSustainedPerfModeOn(false) {
+    mInteractionHandler = std::make_unique<InteractionHandler>();
+    mInteractionHandler->Init();
+
+    std::string state = ::android::base::GetProperty(kPowerHalStateProp, "");
+    if (state == "SUSTAINED_PERFORMANCE") {
+        LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE on";
+        HintManager::GetInstance()->DoHint("SUSTAINED_PERFORMANCE");
+        mSustainedPerfModeOn = true;
+    } else {
+        LOG(INFO) << "Initialize PowerHAL";
+    }
+
+    state = ::android::base::GetProperty(kPowerHalAudioProp, "");
+    if (state == "AUDIO_STREAMING_LOW_LATENCY") {
+        LOG(INFO) << "Initialize with AUDIO_LOW_LATENCY on";
+        HintManager::GetInstance()->DoHint(state);
+    }
+
+    state = ::android::base::GetProperty(kPowerHalRenderingProp, "");
+    if (state == "EXPENSIVE_RENDERING") {
+        LOG(INFO) << "Initialize with EXPENSIVE_RENDERING on";
+        HintManager::GetInstance()->DoHint("EXPENSIVE_RENDERING");
+    }
+}
+
+ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
+    LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled;
+    if (HintManager::GetInstance()->GetAdpfProfile() &&
+        HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs > 0) {
+        PowerSessionManager::getInstance()->updateHintMode(toString(type), enabled);
+    }
+    switch (type) {
+        case Mode::SUSTAINED_PERFORMANCE:
+            if (enabled) {
+                HintManager::GetInstance()->DoHint("SUSTAINED_PERFORMANCE");
+            }
+            mSustainedPerfModeOn = true;
+            break;
+        case Mode::LAUNCH:
+            if (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]];
+        default:
+            if (enabled) {
+                HintManager::GetInstance()->DoHint(toString(type));
+            } else {
+                HintManager::GetInstance()->EndHint(toString(type));
+            }
+            break;
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::isModeSupported(Mode type, bool *_aidl_return) {
+    bool supported = HintManager::GetInstance()->IsHintSupported(toString(type));
+    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;
+    if (HintManager::GetInstance()->GetAdpfProfile() &&
+        HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs > 0) {
+        PowerSessionManager::getInstance()->updateHintBoost(toString(type), durationMs);
+    }
+    switch (type) {
+        case Boost::INTERACTION:
+            if (mSustainedPerfModeOn) {
+                break;
+            }
+            mInteractionHandler->Acquire(durationMs);
+            break;
+        case Boost::DISPLAY_UPDATE_IMMINENT:
+            [[fallthrough]];
+        case Boost::ML_ACC:
+            [[fallthrough]];
+        case Boost::AUDIO_LAUNCH:
+            [[fallthrough]];
+        default:
+            if (mSustainedPerfModeOn) {
+                break;
+            }
+            if (durationMs > 0) {
+                HintManager::GetInstance()->DoHint(toString(type),
+                                                   std::chrono::milliseconds(durationMs));
+            } else if (durationMs == 0) {
+                HintManager::GetInstance()->DoHint(toString(type));
+            } else {
+                HintManager::GetInstance()->EndHint(toString(type));
+            }
+            break;
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool *_aidl_return) {
+    bool supported = HintManager::GetInstance()->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"
+            "SustainedPerformanceMode: %s\n",
+            boolToString(HintManager::GetInstance()->IsRunning()),
+            boolToString(mSustainedPerfModeOn)));
+    // Dump nodes through libperfmgr
+    HintManager::GetInstance()->DumpToFd(fd);
+    PowerSessionManager::getInstance()->dumpToFd(fd);
+    if (!::android::base::WriteStringToFd(buf, fd)) {
+        PLOG(ERROR) << "Failed to dump state to fd";
+    }
+    fsync(fd);
+    return STATUS_OK;
+}
+
+ndk::ScopedAStatus Power::createHintSession(int32_t tgid, int32_t uid,
+                                            const std::vector<int32_t> &threadIds,
+                                            int64_t durationNanos,
+                                            std::shared_ptr<IPowerHintSession> *_aidl_return) {
+    if (!HintManager::GetInstance()->GetAdpfProfile() ||
+        HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs <= 0) {
+        *_aidl_return = nullptr;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+    if (threadIds.size() == 0) {
+        LOG(ERROR) << "Error: threadIds.size() shouldn't be " << threadIds.size();
+        *_aidl_return = nullptr;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    std::shared_ptr<IPowerHintSession> session = ndk::SharedRefBase::make<PowerHintSession>(
+            tgid, uid, threadIds, durationNanos);
+    *_aidl_return = session;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t *outNanoseconds) {
+    *outNanoseconds = HintManager::GetInstance()->GetAdpfProfile()
+                              ? HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs
+                              : 0;
+    if (*outNanoseconds <= 0) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+
+    return ndk::ScopedAStatus::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 0000000..c5bb2a8
--- /dev/null
+++ b/aidl/power-libperfmgr/Power.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <aidl/android/hardware/power/BnPower.h>
+
+#include <atomic>
+#include <memory>
+#include <thread>
+
+#include "InteractionHandler.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::aidl::android::hardware::power::Boost;
+using ::aidl::android::hardware::power::IPowerHintSession;
+using ::aidl::android::hardware::power::Mode;
+
+class Power : public ::aidl::android::hardware::power::BnPower {
+  public:
+    Power();
+    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;
+    ndk::ScopedAStatus createHintSession(int32_t tgid, int32_t uid,
+                                         const std::vector<int32_t> &threadIds,
+                                         int64_t durationNanos,
+                                         std::shared_ptr<IPowerHintSession> *_aidl_return) override;
+    ndk::ScopedAStatus getHintSessionPreferredRate(int64_t *outNanoseconds) override;
+    binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
+
+  private:
+    std::unique_ptr<InteractionHandler> mInteractionHandler;
+    std::atomic<bool> 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 0000000..e6f19d2
--- /dev/null
+++ b/aidl/power-libperfmgr/PowerExt.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.xiaomi.ext-libperfmgr"
+
+#include "PowerExt.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <perfmgr/HintManager.h>
+#include <utils/Log.h>
+
+#include <mutex>
+
+#include "PowerSessionManager.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::android::perfmgr::HintManager;
+
+ndk::ScopedAStatus PowerExt::setMode(const std::string &mode, bool enabled) {
+    LOG(DEBUG) << "PowerExt setMode: " << mode << " to: " << enabled;
+
+    if (enabled) {
+        HintManager::GetInstance()->DoHint(mode);
+    } else {
+        HintManager::GetInstance()->EndHint(mode);
+    }
+    if (HintManager::GetInstance()->GetAdpfProfile() &&
+        HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs > 0) {
+        PowerSessionManager::getInstance()->updateHintMode(mode, enabled);
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerExt::isModeSupported(const std::string &mode, bool *_aidl_return) {
+    bool supported = HintManager::GetInstance()->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;
+    if (HintManager::GetInstance()->GetAdpfProfile() &&
+        HintManager::GetInstance()->GetAdpfProfile()->mReportingRateLimitNs > 0) {
+        PowerSessionManager::getInstance()->updateHintBoost(boost, durationMs);
+    }
+
+    if (durationMs > 0) {
+        HintManager::GetInstance()->DoHint(boost, std::chrono::milliseconds(durationMs));
+    } else if (durationMs == 0) {
+        HintManager::GetInstance()->DoHint(boost);
+    } else {
+        HintManager::GetInstance()->EndHint(boost);
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerExt::isBoostSupported(const std::string &boost, bool *_aidl_return) {
+    bool supported = HintManager::GetInstance()->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 0000000..bed12b5
--- /dev/null
+++ b/aidl/power-libperfmgr/PowerExt.h
@@ -0,0 +1,49 @@
+/*
+ * 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 <atomic>
+#include <memory>
+#include <thread>
+
+#include <aidl/google/hardware/power/extension/pixel/BnPowerExt.h>
+#include <perfmgr/HintManager.h>
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+class PowerExt : public ::aidl::google::hardware::power::extension::pixel::BnPowerExt {
+  public:
+    PowerExt() {}
+    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:
+};
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/PowerHintSession.cpp b/aidl/power-libperfmgr/PowerHintSession.cpp
new file mode 100644
index 0000000..0ac0b4a
--- /dev/null
+++ b/aidl/power-libperfmgr/PowerHintSession.cpp
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2021 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 "powerhal-libperfmgr"
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+
+#include "PowerHintSession.h"
+
+#include <android-base/logging.h>
+#include <android-base/parsedouble.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <perfmgr/AdpfConfig.h>
+#include <private/android_filesystem_config.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <utils/Trace.h>
+
+#include <atomic>
+
+#include "PowerSessionManager.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::android::base::StringPrintf;
+using ::android::perfmgr::AdpfConfig;
+using ::android::perfmgr::HintManager;
+using std::chrono::duration_cast;
+using std::chrono::nanoseconds;
+
+namespace {
+
+static inline int64_t ns_to_100us(int64_t ns) {
+    return ns / 100000;
+}
+
+static int64_t convertWorkDurationToBoostByPid(std::shared_ptr<AdpfConfig> adpfConfig,
+                                               nanoseconds targetDuration,
+                                               const std::vector<WorkDuration> &actualDurations,
+                                               int64_t *integral_error, int64_t *previous_error,
+                                               const std::string &idstr) {
+    uint64_t samplingWindowP = adpfConfig->mSamplingWindowP;
+    uint64_t samplingWindowI = adpfConfig->mSamplingWindowI;
+    uint64_t samplingWindowD = adpfConfig->mSamplingWindowD;
+    int64_t targetDurationNanos = (int64_t)targetDuration.count();
+    int64_t length = actualDurations.size();
+    int64_t p_start =
+            samplingWindowP == 0 || samplingWindowP > length ? 0 : length - samplingWindowP;
+    int64_t i_start =
+            samplingWindowI == 0 || samplingWindowI > length ? 0 : length - samplingWindowI;
+    int64_t d_start =
+            samplingWindowD == 0 || samplingWindowD > length ? 0 : length - samplingWindowD;
+    int64_t dt = ns_to_100us(targetDurationNanos);
+    int64_t err_sum = 0;
+    int64_t derivative_sum = 0;
+    for (int64_t i = std::min({p_start, i_start, d_start}); i < length; i++) {
+        int64_t actualDurationNanos = actualDurations[i].durationNanos;
+        if (std::abs(actualDurationNanos) > targetDurationNanos * 20) {
+            ALOGW("The actual duration is way far from the target (%" PRId64 " >> %" PRId64 ")",
+                  actualDurationNanos, targetDurationNanos);
+        }
+        // PID control algorithm
+        int64_t error = ns_to_100us(actualDurationNanos - targetDurationNanos);
+        if (i >= d_start) {
+            derivative_sum += error - (*previous_error);
+        }
+        if (i >= p_start) {
+            err_sum += error;
+        }
+        if (i >= i_start) {
+            *integral_error = *integral_error + error * dt;
+            *integral_error = std::min(adpfConfig->getPidIHighDivI(), *integral_error);
+            *integral_error = std::max(adpfConfig->getPidILowDivI(), *integral_error);
+        }
+        *previous_error = error;
+    }
+    int64_t pOut = static_cast<int64_t>((err_sum > 0 ? adpfConfig->mPidPo : adpfConfig->mPidPu) *
+                                        err_sum / (length - p_start));
+    int64_t iOut = static_cast<int64_t>(adpfConfig->mPidI * (*integral_error));
+    int64_t dOut =
+            static_cast<int64_t>((derivative_sum > 0 ? adpfConfig->mPidDo : adpfConfig->mPidDu) *
+                                 derivative_sum / dt / (length - d_start));
+
+    int64_t output = pOut + iOut + dOut;
+    if (ATRACE_ENABLED()) {
+        std::string sz = StringPrintf("adpf.%s-pid.err", idstr.c_str());
+        ATRACE_INT(sz.c_str(), err_sum / (length - p_start));
+        sz = StringPrintf("adpf.%s-pid.integral", idstr.c_str());
+        ATRACE_INT(sz.c_str(), *integral_error);
+        sz = StringPrintf("adpf.%s-pid.derivative", idstr.c_str());
+        ATRACE_INT(sz.c_str(), derivative_sum / dt / (length - d_start));
+        sz = StringPrintf("adpf.%s-pid.pOut", idstr.c_str());
+        ATRACE_INT(sz.c_str(), pOut);
+        sz = StringPrintf("adpf.%s-pid.iOut", idstr.c_str());
+        ATRACE_INT(sz.c_str(), iOut);
+        sz = StringPrintf("adpf.%s-pid.dOut", idstr.c_str());
+        ATRACE_INT(sz.c_str(), dOut);
+        sz = StringPrintf("adpf.%s-pid.output", idstr.c_str());
+        ATRACE_INT(sz.c_str(), output);
+    }
+    return output;
+}
+
+}  // namespace
+
+PowerHintSession::PowerHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds,
+                                   int64_t durationNanos) {
+    mDescriptor = new AppHintDesc(tgid, uid, threadIds);
+    mDescriptor->duration = std::chrono::nanoseconds(durationNanos);
+    mStaleTimerHandler = sp<StaleTimerHandler>(new StaleTimerHandler(this));
+    mEarlyBoostHandler = sp<EarlyBoostHandler>(new EarlyBoostHandler(this));
+    mPowerManagerHandler = PowerSessionManager::getInstance();
+    mLastUpdatedTime.store(std::chrono::steady_clock::now());
+    mLastStartedTimeNs =
+            std::chrono::duration_cast<std::chrono::nanoseconds>(
+                    (std::chrono::steady_clock::now() - mDescriptor->duration).time_since_epoch())
+                    .count();
+    mLastDurationNs = durationNanos;
+    mWorkPeriodNs = durationNanos;
+
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-target", idstr.c_str());
+        ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count());
+        sz = StringPrintf("adpf.%s-active", idstr.c_str());
+        ATRACE_INT(sz.c_str(), mDescriptor->is_active.load());
+    }
+    PowerSessionManager::getInstance()->addPowerSession(this);
+    // init boost
+    setSessionUclampMin(HintManager::GetInstance()->GetAdpfProfile()->mUclampMinInit);
+    ALOGV("PowerHintSession created: %s", mDescriptor->toString().c_str());
+}
+
+PowerHintSession::~PowerHintSession() {
+    close();
+    ALOGV("PowerHintSession deleted: %s", mDescriptor->toString().c_str());
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-target", idstr.c_str());
+        ATRACE_INT(sz.c_str(), 0);
+        sz = StringPrintf("adpf.%s-actl_last", idstr.c_str());
+        ATRACE_INT(sz.c_str(), 0);
+        sz = sz = StringPrintf("adpf.%s-active", idstr.c_str());
+        ATRACE_INT(sz.c_str(), 0);
+    }
+    delete mDescriptor;
+}
+
+std::string PowerHintSession::getIdString() const {
+    std::string idstr = StringPrintf("%" PRId32 "-%" PRId32 "-%" PRIxPTR, mDescriptor->tgid,
+                                     mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff);
+    return idstr;
+}
+
+bool PowerHintSession::isAppSession() {
+    // Check if uid is in range reserved for applications
+    return mDescriptor->uid >= AID_APP_START;
+}
+
+void PowerHintSession::updateUniveralBoostMode() {
+    if (!isAppSession()) {
+        return;
+    }
+    if (ATRACE_ENABLED()) {
+        const std::string tag = StringPrintf("%s:updateUniveralBoostMode()", getIdString().c_str());
+        ATRACE_BEGIN(tag.c_str());
+    }
+    PowerHintMonitor::getInstance()->getLooper()->sendMessage(mPowerManagerHandler, NULL);
+    if (ATRACE_ENABLED()) {
+        ATRACE_END();
+    }
+}
+
+int PowerHintSession::setSessionUclampMin(int32_t min) {
+    {
+        std::lock_guard<std::mutex> guard(mSessionLock);
+        mDescriptor->current_min = min;
+    }
+    if (min) {
+        mStaleTimerHandler->updateTimer();
+    }
+    PowerSessionManager::getInstance()->setUclampMin(this, min);
+
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-min", idstr.c_str());
+        ATRACE_INT(sz.c_str(), min);
+    }
+    return 0;
+}
+
+int PowerHintSession::getUclampMin() {
+    return mDescriptor->current_min;
+}
+
+void PowerHintSession::dumpToStream(std::ostream &stream) {
+    stream << "ID.Min.Act.Timeout(" << getIdString();
+    stream << ", " << mDescriptor->current_min;
+    stream << ", " << mDescriptor->is_active;
+    stream << ", " << isTimeout() << ")";
+}
+
+ndk::ScopedAStatus PowerHintSession::pause() {
+    if (mSessionClosed) {
+        ALOGE("Error: session is dead");
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (!mDescriptor->is_active.load())
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    // Reset to default uclamp value.
+    mDescriptor->is_active.store(false);
+    setStale();
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-active", idstr.c_str());
+        ATRACE_INT(sz.c_str(), mDescriptor->is_active.load());
+    }
+    updateUniveralBoostMode();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerHintSession::resume() {
+    if (mSessionClosed) {
+        ALOGE("Error: session is dead");
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (mDescriptor->is_active.load())
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    mDescriptor->is_active.store(true);
+    // resume boost
+    setSessionUclampMin(mDescriptor->current_min);
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-active", idstr.c_str());
+        ATRACE_INT(sz.c_str(), mDescriptor->is_active.load());
+    }
+    updateUniveralBoostMode();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerHintSession::close() {
+    bool sessionClosedExpectedToBe = false;
+    if (!mSessionClosed.compare_exchange_strong(sessionClosedExpectedToBe, true)) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    // Remove the session from PowerSessionManager first to avoid racing.
+    PowerSessionManager::getInstance()->removePowerSession(this);
+    setSessionUclampMin(0);
+    {
+        std::lock_guard<std::mutex> guard(mSessionLock);
+        mSessionClosed.store(true);
+    }
+    mDescriptor->is_active.store(false);
+    mEarlyBoostHandler->setSessionDead();
+    mStaleTimerHandler->setSessionDead();
+    updateUniveralBoostMode();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
+    if (mSessionClosed) {
+        ALOGE("Error: session is dead");
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (targetDurationNanos <= 0) {
+        ALOGE("Error: targetDurationNanos(%" PRId64 ") should bigger than 0", targetDurationNanos);
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    targetDurationNanos =
+            targetDurationNanos * HintManager::GetInstance()->GetAdpfProfile()->mTargetTimeFactor;
+    ALOGV("update target duration: %" PRId64 " ns", targetDurationNanos);
+
+    mDescriptor->duration = std::chrono::nanoseconds(targetDurationNanos);
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-target", idstr.c_str());
+        ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count());
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerHintSession::reportActualWorkDuration(
+        const std::vector<WorkDuration> &actualDurations) {
+    if (mSessionClosed) {
+        ALOGE("Error: session is dead");
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (mDescriptor->duration.count() == 0LL) {
+        ALOGE("Expect to call updateTargetWorkDuration() first.");
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    if (actualDurations.size() == 0) {
+        ALOGE("Error: duration.size() shouldn't be %zu.", actualDurations.size());
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (!mDescriptor->is_active.load()) {
+        ALOGE("Error: shouldn't report duration during pause state.");
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    std::shared_ptr<AdpfConfig> adpfConfig = HintManager::GetInstance()->GetAdpfProfile();
+    mDescriptor->update_count++;
+    bool isFirstFrame = isTimeout();
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-batch_size", idstr.c_str());
+        ATRACE_INT(sz.c_str(), actualDurations.size());
+        sz = StringPrintf("adpf.%s-actl_last", idstr.c_str());
+        ATRACE_INT(sz.c_str(), actualDurations.back().durationNanos);
+        sz = StringPrintf("adpf.%s-target", idstr.c_str());
+        ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count());
+        sz = StringPrintf("adpf.%s-hint.count", idstr.c_str());
+        ATRACE_INT(sz.c_str(), mDescriptor->update_count);
+        sz = StringPrintf("adpf.%s-hint.overtime", idstr.c_str());
+        ATRACE_INT(sz.c_str(),
+                   actualDurations.back().durationNanos - mDescriptor->duration.count() > 0);
+    }
+
+    mLastUpdatedTime.store(std::chrono::steady_clock::now());
+    if (isFirstFrame) {
+        updateUniveralBoostMode();
+    }
+
+    if (!adpfConfig->mPidOn) {
+        setSessionUclampMin(adpfConfig->mUclampMinHigh);
+        return ndk::ScopedAStatus::ok();
+    }
+    int64_t output = convertWorkDurationToBoostByPid(
+            adpfConfig, mDescriptor->duration, actualDurations, &(mDescriptor->integral_error),
+            &(mDescriptor->previous_error), getIdString());
+
+    /* apply to all the threads in the group */
+    int next_min = std::min(static_cast<int>(adpfConfig->mUclampMinHigh),
+                            mDescriptor->current_min + static_cast<int>(output));
+    next_min = std::max(static_cast<int>(adpfConfig->mUclampMinLow), next_min);
+    setSessionUclampMin(next_min);
+    mStaleTimerHandler->updateTimer(getStaleTime());
+    if (HintManager::GetInstance()->GetAdpfProfile()->mEarlyBoostOn) {
+        updateWorkPeriod(actualDurations);
+        mEarlyBoostHandler->updateTimer(getEarlyBoostTime());
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+std::string AppHintDesc::toString() const {
+    std::string out =
+            StringPrintf("session %" PRIxPTR "\n", reinterpret_cast<uintptr_t>(this) & 0xffff);
+    const int64_t durationNanos = duration.count();
+    out.append(StringPrintf("  duration: %" PRId64 " ns\n", durationNanos));
+    out.append(StringPrintf("  uclamp.min: %d \n", current_min));
+    out.append(StringPrintf("  uid: %d, tgid: %d\n", uid, tgid));
+
+    out.append("  threadIds: [");
+    bool first = true;
+    for (int tid : threadIds) {
+        if (!first) {
+            out.append(", ");
+        }
+        out.append(std::to_string(tid));
+        first = false;
+    }
+    out.append("]\n");
+    return out;
+}
+
+bool PowerHintSession::isActive() {
+    return mDescriptor->is_active.load();
+}
+
+bool PowerHintSession::isTimeout() {
+    auto now = std::chrono::steady_clock::now();
+    return now >= getStaleTime();
+}
+
+const std::vector<int> &PowerHintSession::getTidList() const {
+    return mDescriptor->threadIds;
+}
+
+void PowerHintSession::setStale() {
+    // Reset to default uclamp value.
+    PowerSessionManager::getInstance()->setUclampMin(this, 0);
+    // Deliver a task to check if all sessions are inactive.
+    updateUniveralBoostMode();
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-min", idstr.c_str());
+        ATRACE_INT(sz.c_str(), 0);
+    }
+}
+
+void PowerHintSession::wakeup() {
+    std::lock_guard<std::mutex> guard(mSessionLock);
+
+    // We only wake up non-paused session
+    if (mSessionClosed || !isActive()) {
+        return;
+    }
+    // Update session's timer
+    mStaleTimerHandler->updateTimer();
+    // Skip uclamp update for stale session
+    if (!isTimeout()) {
+        return;
+    }
+    if (ATRACE_ENABLED()) {
+        std::string tag = StringPrintf("wakeup.%s(a:%d,s:%d)", getIdString().c_str(), isActive(),
+                                       isTimeout());
+        ATRACE_NAME(tag.c_str());
+    }
+    std::shared_ptr<AdpfConfig> adpfConfig = HintManager::GetInstance()->GetAdpfProfile();
+    int min = std::max(mDescriptor->current_min, static_cast<int>(adpfConfig->mUclampMinInit));
+    mDescriptor->current_min = min;
+    PowerSessionManager::getInstance()->setUclampMinLocked(this, min);
+
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = getIdString();
+        std::string sz = StringPrintf("adpf.%s-min", idstr.c_str());
+        ATRACE_INT(sz.c_str(), min);
+    }
+}
+
+void PowerHintSession::updateWorkPeriod(const std::vector<WorkDuration> &actualDurations) {
+    if (actualDurations.size() == 0)
+        return;
+    if (actualDurations.size() >= 2) {
+        const WorkDuration &last = actualDurations[actualDurations.size() - 2];
+        mLastStartedTimeNs = last.timeStampNanos - last.durationNanos;
+    }
+    const WorkDuration &current = actualDurations.back();
+    int64_t curr_start = current.timeStampNanos - current.durationNanos;
+    int64_t period = curr_start - mLastStartedTimeNs;
+    if (period > 0 && period < mDescriptor->duration.count() * 2) {
+        // Accounting workload period with moving average for the last 10 workload.
+        mWorkPeriodNs = 0.9 * mWorkPeriodNs + 0.1 * period;
+        if (ATRACE_ENABLED()) {
+            const std::string idstr = getIdString();
+            std::string sz = StringPrintf("adpf.%s-timer.period", idstr.c_str());
+            ATRACE_INT(sz.c_str(), mWorkPeriodNs);
+        }
+    }
+    mLastStartedTimeNs = curr_start;
+    mLastDurationNs = current.durationNanos;
+}
+
+time_point<steady_clock> PowerHintSession::getEarlyBoostTime() {
+    std::shared_ptr<AdpfConfig> adpfConfig = HintManager::GetInstance()->GetAdpfProfile();
+    int64_t earlyBoostTimeoutNs =
+            (int64_t)mDescriptor->duration.count() * adpfConfig->mEarlyBoostTimeFactor;
+    time_point<steady_clock> nextStartTime =
+            mLastUpdatedTime.load() + nanoseconds(mWorkPeriodNs - mLastDurationNs);
+    return nextStartTime + nanoseconds(earlyBoostTimeoutNs);
+}
+
+time_point<steady_clock> PowerHintSession::getStaleTime() {
+    return mLastUpdatedTime.load() +
+           nanoseconds(static_cast<int64_t>(
+                   mDescriptor->duration.count() *
+                   HintManager::GetInstance()->GetAdpfProfile()->mStaleTimeFactor));
+}
+
+void PowerHintSession::StaleTimerHandler::updateTimer() {
+    time_point<steady_clock> staleTime =
+            std::chrono::steady_clock::now() +
+            nanoseconds(static_cast<int64_t>(
+                    mSession->mDescriptor->duration.count() *
+                    HintManager::GetInstance()->GetAdpfProfile()->mStaleTimeFactor));
+    updateTimer(staleTime);
+}
+
+void PowerHintSession::StaleTimerHandler::updateTimer(time_point<steady_clock> staleTime) {
+    mStaleTime.store(staleTime);
+    {
+        std::lock_guard<std::mutex> guard(mMessageLock);
+        PowerHintMonitor::getInstance()->getLooper()->removeMessages(mSession->mStaleTimerHandler);
+        PowerHintMonitor::getInstance()->getLooper()->sendMessage(mSession->mStaleTimerHandler,
+                                                                  NULL);
+    }
+    mIsMonitoring.store(true);
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = mSession->getIdString();
+        std::string sz = StringPrintf("adpf.%s-timer.stale", idstr.c_str());
+        ATRACE_INT(sz.c_str(), 0);
+    }
+}
+
+void PowerHintSession::StaleTimerHandler::handleMessage(const Message &) {
+    if (mIsSessionDead) {
+        return;
+    }
+    auto now = std::chrono::steady_clock::now();
+    int64_t next =
+            static_cast<int64_t>(duration_cast<nanoseconds>(mStaleTime.load() - now).count());
+    if (next > 0) {
+        // Schedule for the stale timeout check.
+        std::lock_guard<std::mutex> guard(mMessageLock);
+        PowerHintMonitor::getInstance()->getLooper()->removeMessages(mSession->mStaleTimerHandler);
+        PowerHintMonitor::getInstance()->getLooper()->sendMessageDelayed(
+                next, mSession->mStaleTimerHandler, NULL);
+    } else {
+        mSession->setStale();
+        mIsMonitoring.store(false);
+        if (ATRACE_ENABLED()) {
+            const std::string idstr = mSession->getIdString();
+            std::string sz = StringPrintf("adpf.%s-timer.earlyboost", idstr.c_str());
+            ATRACE_INT(sz.c_str(), 0);
+        }
+    }
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = mSession->getIdString();
+        std::string sz = StringPrintf("adpf.%s-timer.stale", idstr.c_str());
+        ATRACE_INT(sz.c_str(), mIsMonitoring ? 0 : 1);
+    }
+}
+
+void PowerHintSession::StaleTimerHandler::setSessionDead() {
+    std::lock_guard<std::mutex> guard(mStaleLock);
+    mIsSessionDead = true;
+    PowerHintMonitor::getInstance()->getLooper()->removeMessages(mSession->mStaleTimerHandler);
+}
+
+void PowerHintSession::EarlyBoostHandler::updateTimer(time_point<steady_clock> boostTime) {
+    mBoostTime.store(boostTime);
+    {
+        std::lock_guard<std::mutex> guard(mMessageLock);
+        PowerHintMonitor::getInstance()->getLooper()->removeMessages(mSession->mEarlyBoostHandler);
+        PowerHintMonitor::getInstance()->getLooper()->sendMessage(mSession->mEarlyBoostHandler,
+                                                                  NULL);
+    }
+    mIsMonitoring.store(true);
+    if (ATRACE_ENABLED()) {
+        const std::string idstr = mSession->getIdString();
+        std::string sz = StringPrintf("adpf.%s-timer.earlyboost", idstr.c_str());
+        ATRACE_INT(sz.c_str(), 1);
+    }
+}
+
+void PowerHintSession::EarlyBoostHandler::handleMessage(const Message &) {
+    std::lock_guard<std::mutex> guard(mBoostLock);
+    if (mIsSessionDead) {
+        return;
+    }
+    auto now = std::chrono::steady_clock::now();
+    int64_t next =
+            static_cast<int64_t>(duration_cast<nanoseconds>(mBoostTime.load() - now).count());
+    if (next > 0) {
+        if (ATRACE_ENABLED()) {
+            const std::string idstr = mSession->getIdString();
+            std::string sz = StringPrintf("adpf.%s-timer.earlyboost", idstr.c_str());
+            ATRACE_INT(sz.c_str(), 1);
+        }
+        std::lock_guard<std::mutex> guard(mMessageLock);
+        PowerHintMonitor::getInstance()->getLooper()->removeMessages(mSession->mEarlyBoostHandler);
+        PowerHintMonitor::getInstance()->getLooper()->sendMessageDelayed(
+                next, mSession->mEarlyBoostHandler, NULL);
+    } else {
+        std::shared_ptr<AdpfConfig> adpfConfig = HintManager::GetInstance()->GetAdpfProfile();
+        PowerSessionManager::getInstance()->setUclampMin(mSession, adpfConfig->mUclampMinHigh);
+        mIsMonitoring.store(false);
+        if (ATRACE_ENABLED()) {
+            const std::string idstr = mSession->getIdString();
+            std::string sz = StringPrintf("adpf.%s-min", idstr.c_str());
+            ATRACE_INT(sz.c_str(), adpfConfig->mUclampMinHigh);
+            sz = StringPrintf("adpf.%s-timer.earlyboost", idstr.c_str());
+            ATRACE_INT(sz.c_str(), 2);
+        }
+    }
+}
+
+void PowerHintSession::EarlyBoostHandler::setSessionDead() {
+    std::lock_guard<std::mutex> guard(mBoostLock);
+    mIsSessionDead = true;
+    PowerHintMonitor::getInstance()->getLooper()->removeMessages(mSession->mEarlyBoostHandler);
+}
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/PowerHintSession.h b/aidl/power-libperfmgr/PowerHintSession.h
new file mode 100644
index 0000000..d922744
--- /dev/null
+++ b/aidl/power-libperfmgr/PowerHintSession.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2021 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 <aidl/android/hardware/power/BnPowerHintSession.h>
+#include <aidl/android/hardware/power/WorkDuration.h>
+#include <utils/Looper.h>
+#include <utils/Thread.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using aidl::android::hardware::power::BnPowerHintSession;
+using aidl::android::hardware::power::WorkDuration;
+using ::android::Message;
+using ::android::MessageHandler;
+using ::android::sp;
+using std::chrono::milliseconds;
+using std::chrono::nanoseconds;
+using std::chrono::steady_clock;
+using std::chrono::time_point;
+
+struct AppHintDesc {
+    AppHintDesc(int32_t tgid, int32_t uid, std::vector<int> threadIds)
+        : tgid(tgid),
+          uid(uid),
+          threadIds(std::move(threadIds)),
+          duration(0LL),
+          current_min(0),
+          is_active(true),
+          update_count(0),
+          integral_error(0),
+          previous_error(0) {}
+    std::string toString() const;
+    const int32_t tgid;
+    const int32_t uid;
+    const std::vector<int> threadIds;
+    nanoseconds duration;
+    int current_min;
+    // status
+    std::atomic<bool> is_active;
+    // pid
+    uint64_t update_count;
+    int64_t integral_error;
+    int64_t previous_error;
+};
+
+class PowerHintSession : public BnPowerHintSession {
+  public:
+    explicit PowerHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds,
+                              int64_t durationNanos);
+    ~PowerHintSession();
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus pause() override;
+    ndk::ScopedAStatus resume() override;
+    ndk::ScopedAStatus updateTargetWorkDuration(int64_t targetDurationNanos) override;
+    ndk::ScopedAStatus reportActualWorkDuration(
+            const std::vector<WorkDuration> &actualDurations) override;
+    bool isActive();
+    bool isTimeout();
+    void wakeup();
+    void setStale();
+    // Is this hint session for a user application
+    bool isAppSession();
+    const std::vector<int> &getTidList() const;
+    int getUclampMin();
+    void dumpToStream(std::ostream &stream);
+
+    void updateWorkPeriod(const std::vector<WorkDuration> &actualDurations);
+    time_point<steady_clock> getEarlyBoostTime();
+    time_point<steady_clock> getStaleTime();
+
+  private:
+    class StaleTimerHandler : public MessageHandler {
+      public:
+        StaleTimerHandler(PowerHintSession *session)
+            : mSession(session), mIsMonitoring(false), mIsSessionDead(false) {}
+        void updateTimer();
+        void updateTimer(time_point<steady_clock> staleTime);
+        void handleMessage(const Message &message) override;
+        void setSessionDead();
+
+      private:
+        PowerHintSession *mSession;
+        std::mutex mStaleLock;
+        std::mutex mMessageLock;
+        std::atomic<time_point<steady_clock>> mStaleTime;
+        std::atomic<bool> mIsMonitoring;
+        bool mIsSessionDead;
+    };
+
+    class EarlyBoostHandler : public MessageHandler {
+      public:
+        EarlyBoostHandler(PowerHintSession *session)
+            : mSession(session), mIsMonitoring(false), mIsSessionDead(false) {}
+        void updateTimer(time_point<steady_clock> boostTime);
+        void handleMessage(const Message &message) override;
+        void setSessionDead();
+
+      private:
+        PowerHintSession *mSession;
+        std::mutex mBoostLock;
+        std::mutex mMessageLock;
+        std::atomic<time_point<steady_clock>> mBoostTime;
+        std::atomic<bool> mIsMonitoring;
+        bool mIsSessionDead;
+    };
+
+  private:
+    void updateUniveralBoostMode();
+    int setSessionUclampMin(int32_t min);
+    std::string getIdString() const;
+    AppHintDesc *mDescriptor = nullptr;
+    sp<StaleTimerHandler> mStaleTimerHandler;
+    sp<EarlyBoostHandler> mEarlyBoostHandler;
+    std::atomic<time_point<steady_clock>> mLastUpdatedTime;
+    sp<MessageHandler> mPowerManagerHandler;
+    std::mutex mSessionLock;
+    std::atomic<bool> mSessionClosed = false;
+    // These 3 variables are for earlyboost work period estimation.
+    int64_t mLastStartedTimeNs;
+    int64_t mLastDurationNs;
+    int64_t mWorkPeriodNs;
+};
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/PowerSessionManager.cpp b/aidl/power-libperfmgr/PowerSessionManager.cpp
new file mode 100644
index 0000000..516942a
--- /dev/null
+++ b/aidl/power-libperfmgr/PowerSessionManager.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2021 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 "powerhal-libperfmgr"
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+
+#include "PowerSessionManager.h"
+
+#include <android-base/file.h>
+#include <log/log.h>
+#include <perfmgr/HintManager.h>
+#include <processgroup/processgroup.h>
+#include <sys/syscall.h>
+#include <utils/Trace.h>
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::android::perfmgr::HintManager;
+
+namespace {
+/* there is no glibc or bionic wrapper */
+struct sched_attr {
+    __u32 size;
+    __u32 sched_policy;
+    __u64 sched_flags;
+    __s32 sched_nice;
+    __u32 sched_priority;
+    __u64 sched_runtime;
+    __u64 sched_deadline;
+    __u64 sched_period;
+    __u32 sched_util_min;
+    __u32 sched_util_max;
+};
+
+static int sched_setattr(int pid, struct sched_attr *attr, unsigned int flags) {
+    if (!HintManager::GetInstance()->GetAdpfProfile()->mUclampMinOn) {
+        ALOGV("PowerSessionManager:%s: skip", __func__);
+        return 0;
+    }
+    return syscall(__NR_sched_setattr, pid, attr, flags);
+}
+
+static void set_uclamp_min(int tid, int min) {
+    static constexpr int32_t kMaxUclampValue = 1024;
+    min = std::max(0, min);
+    min = std::min(min, kMaxUclampValue);
+
+    sched_attr attr = {};
+    attr.size = sizeof(attr);
+
+    attr.sched_flags = (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN);
+    attr.sched_util_min = min;
+
+    int ret = sched_setattr(tid, &attr, 0);
+    if (ret) {
+        ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno);
+    }
+}
+}  // namespace
+
+void PowerSessionManager::updateHintMode(const std::string &mode, bool enabled) {
+    ALOGV("PowerSessionManager::updateHintMode: mode: %s, enabled: %d", mode.c_str(), enabled);
+    if (enabled && mode.compare(0, 8, "REFRESH_") == 0) {
+        if (mode.compare("REFRESH_120FPS") == 0) {
+            mDisplayRefreshRate = 120;
+        } else if (mode.compare("REFRESH_90FPS") == 0) {
+            mDisplayRefreshRate = 90;
+        } else if (mode.compare("REFRESH_60FPS") == 0) {
+            mDisplayRefreshRate = 60;
+        }
+    }
+    if (HintManager::GetInstance()->GetAdpfProfile()) {
+        HintManager::GetInstance()->SetAdpfProfile(mode);
+    }
+}
+
+void PowerSessionManager::updateHintBoost(const std::string &boost, int32_t durationMs) {
+    ATRACE_CALL();
+    ALOGV("PowerSessionManager::updateHintBoost: boost: %s, durationMs: %d", boost.c_str(),
+          durationMs);
+    if (boost.compare("DISPLAY_UPDATE_IMMINENT") == 0) {
+        PowerHintMonitor::getInstance()->getLooper()->sendMessage(mWakeupHandler, NULL);
+    }
+}
+
+void PowerSessionManager::wakeSessions() {
+    std::lock_guard<std::mutex> guard(mLock);
+    for (PowerHintSession *s : mSessions) {
+        s->wakeup();
+    }
+}
+
+int PowerSessionManager::getDisplayRefreshRate() {
+    return mDisplayRefreshRate;
+}
+
+void PowerSessionManager::addPowerSession(PowerHintSession *session) {
+    std::lock_guard<std::mutex> guard(mLock);
+    for (auto t : session->getTidList()) {
+        mTidSessionListMap[t].insert(session);
+        if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) {
+            if (!SetTaskProfiles(t, {"ResetUclampGrp"})) {
+                ALOGW("Failed to set ResetUclampGrp task profile for tid:%d", t);
+            } else {
+                mTidRefCountMap[t] = 1;
+            }
+            continue;
+        }
+        if (mTidRefCountMap[t] <= 0) {
+            ALOGE("Error! Unexpected zero/negative RefCount:%d for tid:%d", mTidRefCountMap[t], t);
+            continue;
+        }
+        mTidRefCountMap[t]++;
+    }
+    mSessions.insert(session);
+}
+
+void PowerSessionManager::removePowerSession(PowerHintSession *session) {
+    std::lock_guard<std::mutex> guard(mLock);
+    for (auto t : session->getTidList()) {
+        if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) {
+            ALOGE("Unexpected Error! Failed to look up tid:%d in TidRefCountMap", t);
+            continue;
+        }
+        mTidSessionListMap[t].erase(session);
+        mTidRefCountMap[t]--;
+        if (mTidRefCountMap[t] <= 0) {
+            if (!SetTaskProfiles(t, {"NoResetUclampGrp"})) {
+                ALOGW("Failed to set NoResetUclampGrp task profile for tid:%d", t);
+            }
+            mTidRefCountMap.erase(t);
+        }
+    }
+    mSessions.erase(session);
+}
+
+void PowerSessionManager::setUclampMin(PowerHintSession *session, int val) {
+    std::lock_guard<std::mutex> guard(mLock);
+    setUclampMinLocked(session, val);
+}
+
+void PowerSessionManager::setUclampMinLocked(PowerHintSession *session, int val) {
+    for (auto t : session->getTidList()) {
+        // Get thex max uclamp.min across sessions which include the tid.
+        int tidMax = 0;
+        for (PowerHintSession *s : mTidSessionListMap[t]) {
+            if (!s->isActive() || s->isTimeout())
+                continue;
+            tidMax = std::max(tidMax, s->getUclampMin());
+        }
+        set_uclamp_min(t, std::max(val, tidMax));
+    }
+}
+
+std::optional<bool> PowerSessionManager::isAnyAppSessionActive() {
+    std::lock_guard<std::mutex> guard(mLock);
+    bool active = false;
+    for (PowerHintSession *s : mSessions) {
+        // session active and not stale is actually active.
+        if (s->isActive() && !s->isTimeout() && s->isAppSession()) {
+            active = true;
+            break;
+        }
+    }
+    if (active == mActive) {
+        return std::nullopt;
+    } else {
+        mActive = active;
+    }
+
+    return active;
+}
+
+void PowerSessionManager::handleMessage(const Message &) {
+    auto active = isAnyAppSessionActive();
+    if (!active.has_value()) {
+        return;
+    }
+    if (active.value()) {
+        disableSystemTopAppBoost();
+    } else {
+        enableSystemTopAppBoost();
+    }
+}
+
+void PowerSessionManager::WakeupHandler::handleMessage(const Message &) {
+    PowerSessionManager::getInstance()->wakeSessions();
+}
+
+void PowerSessionManager::dumpToFd(int fd) {
+    std::ostringstream dump_buf;
+    std::lock_guard<std::mutex> guard(mLock);
+    dump_buf << "========== Begin PowerSessionManager ADPF list ==========\n";
+    for (PowerHintSession *s : mSessions) {
+        s->dumpToStream(dump_buf);
+        dump_buf << " Tid:Ref[";
+        for (size_t i = 0, len = s->getTidList().size(); i < len; i++) {
+            int t = s->getTidList()[i];
+            dump_buf << t << ":" << mTidSessionListMap[t].size();
+            if (i < len - 1) {
+                dump_buf << ", ";
+            }
+        }
+        dump_buf << "]\n";
+    }
+    dump_buf << "========== End PowerSessionManager ADPF list ==========\n";
+    if (!::android::base::WriteStringToFd(dump_buf.str(), fd)) {
+        ALOGE("Failed to dump one of session list to fd:%d", fd);
+    }
+}
+
+void PowerSessionManager::enableSystemTopAppBoost() {
+    if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
+        ALOGV("PowerSessionManager::enableSystemTopAppBoost!!");
+        HintManager::GetInstance()->EndHint(kDisableBoostHintName);
+    }
+}
+
+void PowerSessionManager::disableSystemTopAppBoost() {
+    if (HintManager::GetInstance()->IsHintSupported(kDisableBoostHintName)) {
+        ALOGV("PowerSessionManager::disableSystemTopAppBoost!!");
+        HintManager::GetInstance()->DoHint(kDisableBoostHintName);
+    }
+}
+
+// =========== PowerHintMonitor implementation start from here ===========
+void PowerHintMonitor::start() {
+    if (!isRunning()) {
+        run("PowerHintMonitor", ::android::PRIORITY_HIGHEST);
+    }
+}
+
+bool PowerHintMonitor::threadLoop() {
+    while (true) {
+        mLooper->pollOnce(-1);
+    }
+    return true;
+}
+
+sp<Looper> PowerHintMonitor::getLooper() {
+    return mLooper;
+}
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/PowerSessionManager.h b/aidl/power-libperfmgr/PowerSessionManager.h
new file mode 100644
index 0000000..6cd0886
--- /dev/null
+++ b/aidl/power-libperfmgr/PowerSessionManager.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2021 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 <android-base/properties.h>
+#include <perfmgr/HintManager.h>
+#include <utils/Looper.h>
+
+#include <mutex>
+#include <optional>
+#include <unordered_set>
+
+#include "PowerHintSession.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::android::Looper;
+using ::android::Message;
+using ::android::MessageHandler;
+using ::android::Thread;
+using ::android::perfmgr::HintManager;
+
+constexpr char kPowerHalAdpfDisableTopAppBoost[] = "vendor.powerhal.adpf.disable.hint";
+
+class PowerSessionManager : public MessageHandler {
+  public:
+    // current hint info
+    void updateHintMode(const std::string &mode, bool enabled);
+    void updateHintBoost(const std::string &boost, int32_t durationMs);
+    int getDisplayRefreshRate();
+    // monitoring session status
+    void addPowerSession(PowerHintSession *session);
+    void removePowerSession(PowerHintSession *session);
+    void setUclampMin(PowerHintSession *session, int min);
+    void setUclampMinLocked(PowerHintSession *session, int min);
+    void handleMessage(const Message &message) override;
+    void dumpToFd(int fd);
+
+    // Singleton
+    static sp<PowerSessionManager> getInstance() {
+        static sp<PowerSessionManager> instance = new PowerSessionManager();
+        return instance;
+    }
+
+  private:
+    class WakeupHandler : public MessageHandler {
+      public:
+        WakeupHandler() {}
+        void handleMessage(const Message &message) override;
+    };
+
+  private:
+    void wakeSessions();
+    std::optional<bool> isAnyAppSessionActive();
+    void disableSystemTopAppBoost();
+    void enableSystemTopAppBoost();
+    const std::string kDisableBoostHintName;
+
+    std::unordered_set<PowerHintSession *> mSessions;  // protected by mLock
+    std::unordered_map<int, int> mTidRefCountMap;      // protected by mLock
+    std::unordered_map<int, std::unordered_set<PowerHintSession *>> mTidSessionListMap;
+    sp<WakeupHandler> mWakeupHandler;
+    bool mActive;  // protected by mLock
+    /**
+     * mLock to pretect the above data objects opertions.
+     **/
+    std::mutex mLock;
+    int mDisplayRefreshRate;
+    // Singleton
+    PowerSessionManager()
+        : kDisableBoostHintName(::android::base::GetProperty(kPowerHalAdpfDisableTopAppBoost,
+                                                             "ADPF_DISABLE_TA_BOOST")),
+          mActive(false),
+          mDisplayRefreshRate(60) {
+        mWakeupHandler = sp<WakeupHandler>(new WakeupHandler());
+    }
+    PowerSessionManager(PowerSessionManager const &) = delete;
+    void operator=(PowerSessionManager const &) = delete;
+};
+
+class PowerHintMonitor : public Thread {
+  public:
+    void start();
+    bool threadLoop() override;
+    sp<Looper> getLooper();
+    // Singleton
+    static sp<PowerHintMonitor> getInstance() {
+        static sp<PowerHintMonitor> instance = new PowerHintMonitor();
+        return instance;
+    }
+    PowerHintMonitor(PowerHintMonitor const &) = delete;
+    void operator=(PowerHintMonitor const &) = delete;
+
+  private:
+    sp<Looper> mLooper;
+    // Singleton
+    PowerHintMonitor() : Thread(false), mLooper(new Looper(true)) {}
+};
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/android.hardware.power-service.RM6785-libperfmgr.rc b/aidl/power-libperfmgr/android.hardware.power-service.RM6785-libperfmgr.rc
new file mode 100644
index 0000000..522decd
--- /dev/null
+++ b/aidl/power-libperfmgr/android.hardware.power-service.RM6785-libperfmgr.rc
@@ -0,0 +1,32 @@
+service vendor.power-hal-aidl /vendor/bin/hw/android.hardware.power-service.RM6785-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
+
+# 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}
+
+# Restart powerHAL when debug property set
+on property:ro.debuggable=1 && property:vendor.powerhal.config.debug=*
+    restart vendor.power-hal-aidl
+
+on property:persist.vendor.powerhal.config.debug=*
+    setprop vendor.powerhal.config.debug ${persist.vendor.powerhal.config.debug}
+
diff --git a/aidl/power-libperfmgr/android.hardware.power-service.RM6785.xml b/aidl/power-libperfmgr/android.hardware.power-service.RM6785.xml
new file mode 100644
index 0000000..9f56deb
--- /dev/null
+++ b/aidl/power-libperfmgr/android.hardware.power-service.RM6785.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.power</name>
+        <version>2</version>
+        <fqname>IPower/default</fqname>
+    </hal>
+</manifest>
diff --git a/aidl/power-libperfmgr/service.cpp b/aidl/power-libperfmgr/service.cpp
new file mode 100644
index 0000000..9f4b689
--- /dev/null
+++ b/aidl/power-libperfmgr/service.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "powerhal-libperfmgr"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <perfmgr/HintManager.h>
+
+#include <thread>
+
+#include "Power.h"
+#include "PowerExt.h"
+#include "PowerSessionManager.h"
+
+using aidl::google::hardware::power::impl::pixel::Power;
+using aidl::google::hardware::power::impl::pixel::PowerExt;
+using aidl::google::hardware::power::impl::pixel::PowerHintMonitor;
+using aidl::google::hardware::power::impl::pixel::PowerSessionManager;
+using ::android::perfmgr::HintManager;
+
+constexpr std::string_view kPowerHalInitProp("vendor.powerhal.init");
+
+int main() {
+    // Parse config but do not start the looper
+    std::shared_ptr<HintManager> hm = HintManager::GetInstance();
+    if (!hm) {
+        LOG(FATAL) << "HintManager Init failed";
+    }
+
+    // single thread
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // core service
+    std::shared_ptr<Power> pw = ndk::SharedRefBase::make<Power>();
+    ndk::SpAIBinder pwBinder = pw->asBinder();
+    AIBinder_setMinSchedulerPolicy(pwBinder.get(), SCHED_NORMAL, -20);
+
+    // extension service
+    std::shared_ptr<PowerExt> pwExt = ndk::SharedRefBase::make<PowerExt>();
+    auto pwExtBinder = pwExt->asBinder();
+    AIBinder_setMinSchedulerPolicy(pwExtBinder.get(), SCHED_NORMAL, -20);
+
+    // 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) << "Power HAL AIDL Service with Extension is started.";
+
+    if (HintManager::GetInstance()->GetAdpfProfile()) {
+        PowerHintMonitor::getInstance()->start();
+    }
+
+    std::thread initThread([&]() {
+        ::android::base::WaitForProperty(kPowerHalInitProp.data(), "1");
+        HintManager::GetInstance()->Start();
+    });
+    initThread.detach();
+
+    ABinderProcess_joinThreadPool();
+
+    // should not reach
+    LOG(ERROR) << "Power HAL AIDL Service with Extension just died.";
+    return EXIT_FAILURE;
+}
diff --git a/device.mk b/device.mk
index d837fa2..ab08056 100644
--- a/device.mk
+++ b/device.mk
@@ -231,7 +231,7 @@
 
 # Power
 PRODUCT_PACKAGES += \
-    android.hardware.power-service.example \
+    android.hardware.power-service.RM6785-libperfmgr \
     android.hardware.power@1.3.vendor:64
 
 # Properties
@@ -265,6 +265,8 @@
 
 # Soong namespaces
 PRODUCT_SOONG_NAMESPACES += \
+    hardware/google/interfaces \
+    hardware/google/pixel \
     $(LOCAL_PATH)
 
 # Soundtrigger