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 ¤t = 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