samsung: aidl: Import Pixel Power HAL aidl impl
authorMichael Benedict <michaelbt@live.com>
Sun, 27 Dec 2020 09:45:17 +0000 (16:45 +0700)
committerMichael Benedict <michaelbt@live.com>
Sun, 14 Mar 2021 05:21:44 +0000 (12:21 +0700)
* from tag android-11.0.0_r18

Signed-off-by: Michael Benedict <michaelbt@live.com>
Change-Id: Ic1408f7d68463379514b62ef2f811bd1102467e1

13 files changed:
Android.mk
aidl/Android.mk [new file with mode: 0644]
aidl/power-libperfmgr/Android.bp [new file with mode: 0644]
aidl/power-libperfmgr/InteractionHandler.cpp [new file with mode: 0644]
aidl/power-libperfmgr/InteractionHandler.h [new file with mode: 0644]
aidl/power-libperfmgr/Power.cpp [new file with mode: 0644]
aidl/power-libperfmgr/Power.h [new file with mode: 0644]
aidl/power-libperfmgr/PowerExt.cpp [new file with mode: 0644]
aidl/power-libperfmgr/PowerExt.h [new file with mode: 0644]
aidl/power-libperfmgr/android.hardware.power-service.pixel-libperfmgr.rc [new file with mode: 0644]
aidl/power-libperfmgr/android.hardware.power-service.pixel.xml [new file with mode: 0644]
aidl/power-libperfmgr/device.mk [new file with mode: 0644]
aidl/power-libperfmgr/service.cpp [new file with mode: 0644]

index fc3385bfeb95c8b4da0f66fe3c00bf4dcfbd611d..0ee18ab3fc2b2befd05e1eab8449842070a03d92 100644 (file)
@@ -36,6 +36,7 @@ include $(SAM_ROOT)/wifiloader/Android.mk
 endif
 
 ifeq ($(BOARD_VENDOR),samsung)
+include $(SAM_ROOT)/aidl/Android.mk
 include $(SAM_ROOT)/audio/Android.mk
 include $(SAM_ROOT)/doze/Android.mk
 include $(SAM_ROOT)/hidl/Android.mk
diff --git a/aidl/Android.mk b/aidl/Android.mk
new file mode 100644 (file)
index 0000000..26e32a7
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2019 The LineageOS Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/aidl/power-libperfmgr/Android.bp b/aidl/power-libperfmgr/Android.bp
new file mode 100644 (file)
index 0000000..f2f4a46
--- /dev/null
@@ -0,0 +1,93 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+soong_namespace {
+    imports: [
+        "hardware/google/pixel",
+        "hardware/google/interfaces",
+    ],
+}
+
+cc_library {
+    name: "libdisppower-pixel",
+    proprietary: true,
+    srcs: [
+        "disp-power/DisplayLowPower.cpp",
+        "disp-power/InteractionHandler.cpp",
+    ],
+     shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libperfmgr",
+        "libutils",
+    ],
+}
+
+cc_library_headers {
+    name: "pixel_power_headers",
+    vendor: true,
+    export_include_dirs: ["hidl"],
+}
+
+cc_binary {
+    name: "android.hardware.power@1.3-service.pixel-libperfmgr",
+    relative_install_path: "hw",
+    vintf_fragments: ["hidl/android.hardware.power@1.3-service.pixel.xml"],
+    init_rc: ["hidl/android.hardware.power@1.3-service.pixel-libperfmgr.rc"],
+    srcs: ["hidl/service.cpp", "hidl/Power.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "android.hardware.power@1.0",
+        "android.hardware.power@1.1",
+        "android.hardware.power@1.2",
+        "android.hardware.power@1.3",
+        "libdisppower-pixel",
+        "libperfmgr",
+    ],
+    proprietary: true,
+}
+
+cc_binary {
+    name: "android.hardware.power-service.pixel-libperfmgr",
+    relative_install_path: "hw",
+    init_rc: ["aidl/android.hardware.power-service.pixel-libperfmgr.rc"],
+    vintf_fragments: ["aidl/android.hardware.power-service.pixel.xml"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.power-ndk_platform",
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libbinder_ndk",
+        "libdisppower-pixel",
+        "libperfmgr",
+        "pixel-power-ext-ndk_platform",
+    ],
+    srcs: [
+        "aidl/service.cpp",
+        "aidl/Power.cpp",
+        "aidl/PowerExt.cpp",
+    ],
+}
diff --git a/aidl/power-libperfmgr/InteractionHandler.cpp b/aidl/power-libperfmgr/InteractionHandler.cpp
new file mode 100644 (file)
index 0000000..1826958
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.power@-service.pixel-libperfmgr"
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/eventfd.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <memory>
+
+#include "InteractionHandler.h"
+
+#define MAX_LENGTH 64
+
+#define MSINSEC 1000L
+#define USINMS 1000000L
+
+static const std::vector<std::string> fb_idle_patch = {"/sys/class/drm/card0/device/idle_state",
+                                                       "/sys/class/graphics/fb0/idle_state"};
+
+InteractionHandler::InteractionHandler(std::shared_ptr<HintManager> const &hint_manager)
+    : mState(INTERACTION_STATE_UNINITIALIZED),
+      mWaitMs(100),
+      mMinDurationMs(1400),
+      mMaxDurationMs(5650),
+      mDurationMs(0),
+      mHintManager(hint_manager) {}
+
+InteractionHandler::~InteractionHandler() {
+    Exit();
+}
+
+static int fb_idle_open(void) {
+    int fd;
+    for (auto &path : fb_idle_patch) {
+        fd = open(path.c_str(), O_RDONLY);
+        if (fd >= 0)
+            return fd;
+    }
+    ALOGE("Unable to open fb idle state path (%d)", errno);
+    return -1;
+}
+
+bool InteractionHandler::Init() {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    if (mState != INTERACTION_STATE_UNINITIALIZED)
+        return true;
+
+    int fd = fb_idle_open();
+    if (fd < 0)
+        return false;
+    mIdleFd = fd;
+
+    mEventFd = eventfd(0, EFD_NONBLOCK);
+    if (mEventFd < 0) {
+        ALOGE("Unable to create event fd (%d)", errno);
+        close(mIdleFd);
+        return false;
+    }
+
+    mState = INTERACTION_STATE_IDLE;
+    mThread = std::unique_ptr<std::thread>(new std::thread(&InteractionHandler::Routine, this));
+
+    return true;
+}
+
+void InteractionHandler::Exit() {
+    std::unique_lock<std::mutex> lk(mLock);
+    if (mState == INTERACTION_STATE_UNINITIALIZED)
+        return;
+
+    AbortWaitLocked();
+    mState = INTERACTION_STATE_UNINITIALIZED;
+    lk.unlock();
+
+    mCond.notify_all();
+    mThread->join();
+
+    close(mEventFd);
+    close(mIdleFd);
+}
+
+void InteractionHandler::PerfLock() {
+    ALOGV("%s: acquiring perf lock", __func__);
+    if (!mHintManager->DoHint("INTERACTION")) {
+        ALOGE("%s: do hint INTERACTION failed", __func__);
+    }
+    ATRACE_INT("interaction_lock", 1);
+}
+
+void InteractionHandler::PerfRel() {
+    ALOGV("%s: releasing perf lock", __func__);
+    if (!mHintManager->EndHint("INTERACTION")) {
+        ALOGE("%s: end hint INTERACTION failed", __func__);
+    }
+    ATRACE_INT("interaction_lock", 0);
+}
+
+size_t InteractionHandler::CalcTimespecDiffMs(struct timespec start, struct timespec end) {
+    size_t diff_in_us = 0;
+    diff_in_us += (end.tv_sec - start.tv_sec) * MSINSEC;
+    diff_in_us += (end.tv_nsec - start.tv_nsec) / USINMS;
+    return diff_in_us;
+}
+
+void InteractionHandler::Acquire(int32_t duration) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lk(mLock);
+    if (mState == INTERACTION_STATE_UNINITIALIZED) {
+        ALOGW("%s: called while uninitialized", __func__);
+        return;
+    }
+
+    int inputDuration = duration + 650;
+    int finalDuration;
+    if (inputDuration > mMaxDurationMs)
+        finalDuration = mMaxDurationMs;
+    else if (inputDuration > mMinDurationMs)
+        finalDuration = inputDuration;
+    else
+        finalDuration = mMinDurationMs;
+
+    struct timespec cur_timespec;
+    clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
+    if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
+        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() {
+    std::unique_lock<std::mutex> lk(mLock, std::defer_lock);
+
+    while (true) {
+        lk.lock();
+        mCond.wait(lk, [&] { return mState != INTERACTION_STATE_IDLE; });
+        if (mState == INTERACTION_STATE_UNINITIALIZED)
+            return;
+        mState = INTERACTION_STATE_WAITING;
+        lk.unlock();
+
+        WaitForIdle(mWaitMs, mDurationMs);
+        Release();
+    }
+}
diff --git a/aidl/power-libperfmgr/InteractionHandler.h b/aidl/power-libperfmgr/InteractionHandler.h
new file mode 100644 (file)
index 0000000..ba767f1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
+#define POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include <perfmgr/HintManager.h>
+
+using ::android::perfmgr::HintManager;
+
+enum interaction_state {
+    INTERACTION_STATE_UNINITIALIZED,
+    INTERACTION_STATE_IDLE,
+    INTERACTION_STATE_INTERACTION,
+    INTERACTION_STATE_WAITING,
+};
+
+class InteractionHandler {
+  public:
+    InteractionHandler(std::shared_ptr<HintManager> const &hint_manager);
+    ~InteractionHandler();
+    bool Init();
+    void Exit();
+    void Acquire(int32_t duration);
+
+  private:
+    void Release();
+    void WaitForIdle(int32_t wait_ms, int32_t timeout_ms);
+    void AbortWaitLocked();
+    void Routine();
+
+    void PerfLock();
+    void PerfRel();
+
+    size_t CalcTimespecDiffMs(struct timespec start, struct timespec end);
+
+    enum interaction_state mState;
+
+    int mIdleFd;
+    int mEventFd;
+
+    int32_t mWaitMs;
+    int32_t mMinDurationMs;
+    int32_t mMaxDurationMs;
+    int32_t mDurationMs;
+
+    struct timespec mLastTimespec;
+
+    std::unique_ptr<std::thread> mThread;
+    std::mutex mLock;
+    std::condition_variable mCond;
+    std::shared_ptr<HintManager> mHintManager;
+};
+
+#endif  // POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
diff --git a/aidl/power-libperfmgr/Power.cpp b/aidl/power-libperfmgr/Power.cpp
new file mode 100644 (file)
index 0000000..d944cf4
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+#define LOG_TAG "android.hardware.power-service.pixel-libperfmgr"
+
+#include "Power.h"
+
+#include <mutex>
+
+#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 <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "disp-power/DisplayLowPower.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
+constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
+constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
+
+Power::Power(std::shared_ptr<HintManager> hm, std::shared_ptr<DisplayLowPower> dlpw)
+    : mHintManager(hm),
+      mDisplayLowPower(dlpw),
+      mInteractionHandler(nullptr),
+      mVRModeOn(false),
+      mSustainedPerfModeOn(false) {
+    mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager);
+    mInteractionHandler->Init();
+
+    std::string state = ::android::base::GetProperty(kPowerHalStateProp, "");
+    if (state == "SUSTAINED_PERFORMANCE") {
+        ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
+        mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+        mSustainedPerfModeOn = true;
+    } else if (state == "VR") {
+        ALOGI("Initialize with VR on");
+        mHintManager->DoHint(state);
+        mVRModeOn = true;
+    } else if (state == "VR_SUSTAINED_PERFORMANCE") {
+        ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR on");
+        mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+        mSustainedPerfModeOn = true;
+        mVRModeOn = true;
+    } else {
+        ALOGI("Initialize PowerHAL");
+    }
+
+    state = ::android::base::GetProperty(kPowerHalAudioProp, "");
+    if (state == "AUDIO_STREAMING_LOW_LATENCY") {
+        ALOGI("Initialize with AUDIO_LOW_LATENCY on");
+        mHintManager->DoHint(state);
+    }
+
+    state = ::android::base::GetProperty(kPowerHalRenderingProp, "");
+    if (state == "EXPENSIVE_RENDERING") {
+        ALOGI("Initialize with EXPENSIVE_RENDERING on");
+        mHintManager->DoHint("EXPENSIVE_RENDERING");
+    }
+
+    // Now start to take powerhint
+    ALOGI("PowerHAL ready to process hints");
+}
+
+ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
+    LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled;
+    ATRACE_INT(toString(type).c_str(), enabled);
+    switch (type) {
+        case Mode::LOW_POWER:
+            mDisplayLowPower->SetDisplayLowPower(enabled);
+            if (enabled) {
+                mHintManager->DoHint(toString(type));
+            } else {
+                mHintManager->EndHint(toString(type));
+            }
+            break;
+        case Mode::SUSTAINED_PERFORMANCE:
+            if (enabled && !mSustainedPerfModeOn) {
+                if (!mVRModeOn) {  // Sustained mode only.
+                    mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+                } else {  // Sustained + VR mode.
+                    mHintManager->EndHint("VR");
+                    mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+                }
+                mSustainedPerfModeOn = true;
+            } else if (!enabled && mSustainedPerfModeOn) {
+                mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
+                mHintManager->EndHint("SUSTAINED_PERFORMANCE");
+                if (mVRModeOn) {  // Switch back to VR Mode.
+                    mHintManager->DoHint("VR");
+                }
+                mSustainedPerfModeOn = false;
+            }
+            break;
+        case Mode::VR:
+            if (enabled && !mVRModeOn) {
+                if (!mSustainedPerfModeOn) {  // VR mode only.
+                    mHintManager->DoHint("VR");
+                } else {  // Sustained + VR mode.
+                    mHintManager->EndHint("SUSTAINED_PERFORMANCE");
+                    mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+                }
+                mVRModeOn = true;
+            } else if (!enabled && mVRModeOn) {
+                mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
+                mHintManager->EndHint("VR");
+                if (mSustainedPerfModeOn) {  // Switch back to sustained Mode.
+                    mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+                }
+                mVRModeOn = false;
+            }
+            break;
+        case Mode::LAUNCH:
+            if (mVRModeOn || mSustainedPerfModeOn) {
+                break;
+            }
+            [[fallthrough]];
+        case Mode::DOUBLE_TAP_TO_WAKE:
+            [[fallthrough]];
+        case Mode::FIXED_PERFORMANCE:
+            [[fallthrough]];
+        case Mode::EXPENSIVE_RENDERING:
+            [[fallthrough]];
+        case Mode::INTERACTIVE:
+            [[fallthrough]];
+        case Mode::DEVICE_IDLE:
+            [[fallthrough]];
+        case Mode::DISPLAY_INACTIVE:
+            [[fallthrough]];
+        case Mode::AUDIO_STREAMING_LOW_LATENCY:
+            [[fallthrough]];
+        case Mode::CAMERA_STREAMING_SECURE:
+            [[fallthrough]];
+        case Mode::CAMERA_STREAMING_LOW:
+            [[fallthrough]];
+        case Mode::CAMERA_STREAMING_MID:
+            [[fallthrough]];
+        case Mode::CAMERA_STREAMING_HIGH:
+            [[fallthrough]];
+        default:
+            if (enabled) {
+                mHintManager->DoHint(toString(type));
+            } else {
+                mHintManager->EndHint(toString(type));
+            }
+            break;
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::isModeSupported(Mode type, bool *_aidl_return) {
+    bool supported = mHintManager->IsHintSupported(toString(type));
+    // LOW_POWER handled insides PowerHAL specifically
+    if (type == Mode::LOW_POWER) {
+        supported = true;
+    }
+    LOG(INFO) << "Power mode " << toString(type) << " isModeSupported: " << supported;
+    *_aidl_return = supported;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
+    LOG(DEBUG) << "Power setBoost: " << toString(type) << " duration: " << durationMs;
+    ATRACE_INT(toString(type).c_str(), durationMs);
+    switch (type) {
+        case Boost::INTERACTION:
+            if (mVRModeOn || mSustainedPerfModeOn) {
+                break;
+            }
+            mInteractionHandler->Acquire(durationMs);
+            break;
+        case Boost::DISPLAY_UPDATE_IMMINENT:
+            [[fallthrough]];
+        case Boost::ML_ACC:
+            [[fallthrough]];
+        case Boost::AUDIO_LAUNCH:
+            [[fallthrough]];
+        case Boost::CAMERA_LAUNCH:
+            [[fallthrough]];
+        case Boost::CAMERA_SHOT:
+            [[fallthrough]];
+        default:
+            if (mVRModeOn || mSustainedPerfModeOn) {
+                break;
+            }
+            if (durationMs > 0) {
+                mHintManager->DoHint(toString(type), std::chrono::milliseconds(durationMs));
+            } else if (durationMs == 0) {
+                mHintManager->DoHint(toString(type));
+            } else {
+                mHintManager->EndHint(toString(type));
+            }
+            break;
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool *_aidl_return) {
+    bool supported = mHintManager->IsHintSupported(toString(type));
+    LOG(INFO) << "Power boost " << toString(type) << " isBoostSupported: " << supported;
+    *_aidl_return = supported;
+    return ndk::ScopedAStatus::ok();
+}
+
+constexpr const char *boolToString(bool b) {
+    return b ? "true" : "false";
+}
+
+binder_status_t Power::dump(int fd, const char **, uint32_t) {
+    std::string buf(::android::base::StringPrintf(
+            "HintManager Running: %s\n"
+            "VRMode: %s\n"
+            "SustainedPerformanceMode: %s\n",
+            boolToString(mHintManager->IsRunning()), boolToString(mVRModeOn),
+            boolToString(mSustainedPerfModeOn)));
+    // Dump nodes through libperfmgr
+    mHintManager->DumpToFd(fd);
+    if (!::android::base::WriteStringToFd(buf, fd)) {
+        PLOG(ERROR) << "Failed to dump state to fd";
+    }
+    fsync(fd);
+    return STATUS_OK;
+}
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/Power.h b/aidl/power-libperfmgr/Power.h
new file mode 100644 (file)
index 0000000..8b90cb4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <memory>
+#include <thread>
+
+#include <aidl/android/hardware/power/BnPower.h>
+#include <perfmgr/HintManager.h>
+
+#include "disp-power/DisplayLowPower.h"
+#include "disp-power/InteractionHandler.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::InteractionHandler;
+using ::aidl::android::hardware::power::Boost;
+using ::aidl::android::hardware::power::Mode;
+using ::android::perfmgr::HintManager;
+
+class Power : public ::aidl::android::hardware::power::BnPower {
+  public:
+    Power(std::shared_ptr<HintManager> hm, std::shared_ptr<DisplayLowPower> dlpw);
+    ndk::ScopedAStatus setMode(Mode type, bool enabled) override;
+    ndk::ScopedAStatus isModeSupported(Mode type, bool *_aidl_return) override;
+    ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override;
+    ndk::ScopedAStatus isBoostSupported(Boost type, bool *_aidl_return) override;
+    binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
+
+  private:
+    std::shared_ptr<HintManager> mHintManager;
+    std::shared_ptr<DisplayLowPower> mDisplayLowPower;
+    std::unique_ptr<InteractionHandler> mInteractionHandler;
+    std::atomic<bool> mVRModeOn;
+    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 (file)
index 0000000..24e855d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+#define LOG_TAG "android.hardware.power-service.pixel.ext-libperfmgr"
+
+#include "PowerExt.h"
+
+#include <mutex>
+
+#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 <utils/Log.h>
+#include <utils/Trace.h>
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+ndk::ScopedAStatus PowerExt::setMode(const std::string &mode, bool enabled) {
+    LOG(DEBUG) << "PowerExt setMode: " << mode << " to: " << enabled;
+    ATRACE_INT(mode.c_str(), enabled);
+
+    if (enabled) {
+        mHintManager->DoHint(mode);
+    } else {
+        mHintManager->EndHint(mode);
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerExt::isModeSupported(const std::string &mode, bool *_aidl_return) {
+    bool supported = mHintManager->IsHintSupported(mode);
+    LOG(INFO) << "PowerExt mode " << mode << " isModeSupported: " << supported;
+    *_aidl_return = supported;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerExt::setBoost(const std::string &boost, int32_t durationMs) {
+    LOG(DEBUG) << "PowerExt setBoost: " << boost << " duration: " << durationMs;
+    ATRACE_INT(boost.c_str(), durationMs);
+
+    if (durationMs > 0) {
+        mHintManager->DoHint(boost, std::chrono::milliseconds(durationMs));
+    } else if (durationMs == 0) {
+        mHintManager->DoHint(boost);
+    } else {
+        mHintManager->EndHint(boost);
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerExt::isBoostSupported(const std::string &boost, bool *_aidl_return) {
+    bool supported = mHintManager->IsHintSupported(boost);
+    LOG(INFO) << "PowerExt boost " << boost << " isBoostSupported: " << supported;
+    *_aidl_return = supported;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/PowerExt.h b/aidl/power-libperfmgr/PowerExt.h
new file mode 100644 (file)
index 0000000..65cec2c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <memory>
+#include <thread>
+
+#include <aidl/google/hardware/power/extension/pixel/BnPowerExt.h>
+#include <perfmgr/HintManager.h>
+
+#include "disp-power/DisplayLowPower.h"
+
+namespace aidl {
+namespace google {
+namespace hardware {
+namespace power {
+namespace impl {
+namespace pixel {
+
+using ::android::perfmgr::HintManager;
+
+class PowerExt : public ::aidl::google::hardware::power::extension::pixel::BnPowerExt {
+  public:
+    PowerExt(std::shared_ptr<HintManager> hm, std::shared_ptr<DisplayLowPower> dlpw)
+        : mHintManager(hm), mDisplayLowPower(dlpw) {}
+    ndk::ScopedAStatus setMode(const std::string &mode, bool enabled) override;
+    ndk::ScopedAStatus isModeSupported(const std::string &mode, bool *_aidl_return) override;
+    ndk::ScopedAStatus setBoost(const std::string &boost, int32_t durationMs) override;
+    ndk::ScopedAStatus isBoostSupported(const std::string &boost, bool *_aidl_return) override;
+
+  private:
+    std::shared_ptr<HintManager> mHintManager;
+    std::shared_ptr<DisplayLowPower> mDisplayLowPower;
+};
+
+}  // namespace pixel
+}  // namespace impl
+}  // namespace power
+}  // namespace hardware
+}  // namespace google
+}  // namespace aidl
diff --git a/aidl/power-libperfmgr/android.hardware.power-service.pixel-libperfmgr.rc b/aidl/power-libperfmgr/android.hardware.power-service.pixel-libperfmgr.rc
new file mode 100644 (file)
index 0000000..ef15b12
--- /dev/null
@@ -0,0 +1,29 @@
+service vendor.power-hal-aidl /vendor/bin/hw/android.hardware.power-service.pixel-libperfmgr
+    class hal
+    user root
+    group system
+    priority -20
+
+on late-fs
+     start vendor.power-hal-aidl
+
+# restart powerHAL when framework died
+on property:init.svc.zygote=restarting && property:vendor.powerhal.state=*
+    setprop vendor.powerhal.state ""
+    setprop vendor.powerhal.audio ""
+    setprop vendor.powerhal.rendering ""
+    restart vendor.power-hal-aidl
+
+# restart powerHAL when audioHAL died
+on property:init.svc.vendor.audio-hal-2-0=restarting && property:vendor.powerhal.audio=AUDIO_STREAMING_LOW_LATENCY
+    setprop vendor.powerhal.audio ""
+    restart vendor.power-hal-aidl
+
+# Clean up after b/163539793 resolved
+on property:vendor.powerhal.dalvik.vm.dex2oat-threads=*
+    setprop dalvik.vm.dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads}
+    setprop dalvik.vm.restore-dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads}
+
+on property:vendor.powerhal.dalvik.vm.dex2oat-cpu-set=*
+    setprop dalvik.vm.dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set}
+    setprop dalvik.vm.restore-dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set}
diff --git a/aidl/power-libperfmgr/android.hardware.power-service.pixel.xml b/aidl/power-libperfmgr/android.hardware.power-service.pixel.xml
new file mode 100644 (file)
index 0000000..caf6ea2
--- /dev/null
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.power</name>
+        <fqname>IPower/default</fqname>
+    </hal>
+</manifest>
diff --git a/aidl/power-libperfmgr/device.mk b/aidl/power-libperfmgr/device.mk
new file mode 100644 (file)
index 0000000..c848597
--- /dev/null
@@ -0,0 +1,5 @@
+BOARD_SEPOLICY_DIRS += hardware/google/pixel-sepolicy/power-libperfmgr
+
+# power HAL
+PRODUCT_PACKAGES += \
+    android.hardware.power-service.pixel-libperfmgr
diff --git a/aidl/power-libperfmgr/service.cpp b/aidl/power-libperfmgr/service.cpp
new file mode 100644 (file)
index 0000000..aeb6356
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.power-service.pixel-libperfmgr"
+
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "Power.h"
+#include "PowerExt.h"
+#include "disp-power/DisplayLowPower.h"
+
+using aidl::google::hardware::power::impl::pixel::Power;
+using aidl::google::hardware::power::impl::pixel::PowerExt;
+using ::android::perfmgr::HintManager;
+
+constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json";
+constexpr char kPowerHalInitProp[] = "vendor.powerhal.init";
+
+int main() {
+    LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting.";
+
+    // Parse config but do not start the looper
+    std::shared_ptr<HintManager> hm = HintManager::GetFromJSON(kPowerHalConfigPath, false);
+    if (!hm) {
+        LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath;
+    }
+
+    std::shared_ptr<DisplayLowPower> dlpw = std::make_shared<DisplayLowPower>();
+
+    // single thread
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // core service
+    std::shared_ptr<Power> pw = ndk::SharedRefBase::make<Power>(hm, dlpw);
+    ndk::SpAIBinder pwBinder = pw->asBinder();
+
+    // extension service
+    std::shared_ptr<PowerExt> pwExt = ndk::SharedRefBase::make<PowerExt>(hm, dlpw);
+
+    // attach the extension to the same binder we will be registering
+    CHECK(STATUS_OK == AIBinder_setExtension(pwBinder.get(), pwExt->asBinder().get()));
+
+    const std::string instance = std::string() + Power::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(pw->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+    LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is started.";
+
+    std::thread initThread([&]() {
+        ::android::base::WaitForProperty(kPowerHalInitProp, "1");
+        hm->Start();
+        dlpw->Init();
+    });
+    initThread.detach();
+
+    ABinderProcess_joinThreadPool();
+
+    // should not reach
+    LOG(ERROR) << "Pixel Power HAL AIDL Service with Extension just died.";
+    return EXIT_FAILURE;
+}