samsung: hidl: import Pixel libperfmgr Power HAL
authorJesse Chan <jc@lineageos.org>
Sat, 13 Jun 2020 03:17:52 +0000 (11:17 +0800)
committerJesse Chan <jc@lineageos.org>
Sat, 27 Jun 2020 17:41:00 +0000 (01:41 +0800)
hardware/google/pixel/power-libperfmgr from android-10.0.0_r39

Change-Id: I969f76219e6507627d3689b3c2dc025983bcfde4
Signed-off-by: Jesse Chan <jc@lineageos.org>
12 files changed:
hidl/power-libperfmgr/Android.bp [new file with mode: 0644]
hidl/power-libperfmgr/AudioStreaming.h [new file with mode: 0644]
hidl/power-libperfmgr/CameraMode.h [new file with mode: 0644]
hidl/power-libperfmgr/InteractionHandler.cpp [new file with mode: 0644]
hidl/power-libperfmgr/InteractionHandler.h [new file with mode: 0644]
hidl/power-libperfmgr/Power.cpp [new file with mode: 0644]
hidl/power-libperfmgr/Power.h [new file with mode: 0644]
hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel-libperfmgr.rc [new file with mode: 0644]
hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel.xml [new file with mode: 0644]
hidl/power-libperfmgr/display-helper.cpp [new file with mode: 0644]
hidl/power-libperfmgr/display-helper.h [new file with mode: 0644]
hidl/power-libperfmgr/service.cpp [new file with mode: 0644]

diff --git a/hidl/power-libperfmgr/Android.bp b/hidl/power-libperfmgr/Android.bp
new file mode 100644 (file)
index 0000000..7874d10
--- /dev/null
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "pixel_power_headers",
+    vendor_available: true,
+    export_include_dirs: ["."],
+}
+
+cc_binary {
+    name: "android.hardware.power@1.3-service.pixel-libperfmgr",
+    relative_install_path: "hw",
+    vintf_fragments: ["android.hardware.power@1.3-service.pixel.xml"],
+    init_rc: ["android.hardware.power@1.3-service.pixel-libperfmgr.rc"],
+    srcs: ["service.cpp", "Power.cpp", "InteractionHandler.cpp",
+            "display-helper.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "android.hardware.power@1.0",
+        "android.hardware.power@1.1",
+        "android.hardware.power@1.2",
+        "android.hardware.power@1.3",
+        "libperfmgr",
+    ],
+    proprietary: true,
+}
diff --git a/hidl/power-libperfmgr/AudioStreaming.h b/hidl/power-libperfmgr/AudioStreaming.h
new file mode 100644 (file)
index 0000000..d8772d5
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 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_AUDIOSTREAMING_H_
+#define POWER_LIBPERFMGR_AUDIOSTREAMING_H_
+
+enum AUDIO_STREAMING_HINT {
+    AUDIO_STREAMING_OFF = 0,
+    AUDIO_STREAMING_ON = 1,
+    TPU_BOOST_OFF = 1000,
+    TPU_BOOST_SHORT = 1001,
+    TPU_BOOST_LONG = 1002
+};
+
+enum TPU_HINT_DURATION_MS { SHORT = 200, LONG = 2000 };
+
+#endif  // POWER_LIBPERFMGR_AUDIOSTREAMING_H_
diff --git a/hidl/power-libperfmgr/CameraMode.h b/hidl/power-libperfmgr/CameraMode.h
new file mode 100644 (file)
index 0000000..1e05623
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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_CAMERAMODE_H_
+#define POWER_LIBPERFMGR_CAMERAMODE_H_
+
+enum CameraStreamingMode {
+    CAMERA_STREAMING_OFF = 0,
+    CAMERA_STREAMING,
+    CAMERA_STREAMING_1080P,
+    CAMERA_STREAMING_60FPS,
+    CAMERA_STREAMING_4K,
+    CAMERA_STREAMING_SECURE,
+    CAMERA_STREAMING_MAX
+};
+
+#endif  // POWER_LIBPERFMGR_CAMERAMODE_H_
diff --git a/hidl/power-libperfmgr/InteractionHandler.cpp b/hidl/power-libperfmgr/InteractionHandler.cpp
new file mode 100644 (file)
index 0000000..da6a917
--- /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@1.3-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/hidl/power-libperfmgr/InteractionHandler.h b/hidl/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/hidl/power-libperfmgr/Power.cpp b/hidl/power-libperfmgr/Power.cpp
new file mode 100644 (file)
index 0000000..f199bfb
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * 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 "android.hardware.power@1.3-service.pixel-libperfmgr"
+
+#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 <mutex>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "AudioStreaming.h"
+#include "Power.h"
+#include "display-helper.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::Status;
+
+constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
+constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
+constexpr char kPowerHalInitProp[] = "vendor.powerhal.init";
+constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
+constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json";
+
+static const std::map<enum CameraStreamingMode, std::string> kCamStreamingHint = {
+        {CAMERA_STREAMING_OFF, "CAMERA_STREAMING_OFF"},
+        {CAMERA_STREAMING, "CAMERA_STREAMING"},
+        {CAMERA_STREAMING_1080P, "CAMERA_STREAMING_1080P"},
+        {CAMERA_STREAMING_60FPS, "CAMERA_STREAMING_60FPS"},
+        {CAMERA_STREAMING_4K, "CAMERA_STREAMING_4K"},
+        {CAMERA_STREAMING_SECURE, "CAMERA_STREAMING_SECURE"}};
+
+Power::Power()
+    : mHintManager(nullptr),
+      mInteractionHandler(nullptr),
+      mVRModeOn(false),
+      mSustainedPerfModeOn(false),
+      mCameraStreamingMode(CAMERA_STREAMING_OFF),
+      mReady(false) {
+    mInitThread = std::thread([this]() {
+        android::base::WaitForProperty(kPowerHalInitProp, "1");
+        mHintManager = HintManager::GetFromJSON(kPowerHalConfigPath);
+        if (!mHintManager) {
+            LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath;
+        }
+        mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager);
+        mInteractionHandler->Init();
+        std::string state = android::base::GetProperty(kPowerHalStateProp, "");
+        if (state == "CAMERA_STREAMING") {
+            ALOGI("Initialize with CAMERA_STREAMING on");
+            mHintManager->DoHint("CAMERA_STREAMING");
+            mCameraStreamingMode = CAMERA_STREAMING;
+        } else if (state == "CAMERA_STREAMING_1080P") {
+            ALOGI("Initialize CAMERA_STREAMING_1080P on");
+            mHintManager->DoHint("CAMERA_STREAMING_1080P");
+            mCameraStreamingMode = CAMERA_STREAMING_1080P;
+        } else if (state == "CAMERA_STREAMING_60FPS") {
+            ALOGI("Initialize CAMERA_STREAMING_60FPS on");
+            mHintManager->DoHint("CAMERA_STREAMING_60FPS");
+            mCameraStreamingMode = CAMERA_STREAMING_60FPS;
+        } else if (state == "CAMERA_STREAMING_4K") {
+            ALOGI("Initialize with CAMERA_STREAMING_4K on");
+            mHintManager->DoHint("CAMERA_STREAMING_4K");
+            mCameraStreamingMode = CAMERA_STREAMING_4K;
+        } else if (state == "CAMERA_STREAMING_SECURE") {
+            ALOGI("Initialize with CAMERA_STREAMING_SECURE on");
+            mHintManager->DoHint("CAMERA_STREAMING_SECURE");
+            mCameraStreamingMode = CAMERA_STREAMING_SECURE;
+        } else if (state == "SUSTAINED_PERFORMANCE") {
+            ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
+            mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+            mSustainedPerfModeOn = true;
+        } else if (state == "VR_MODE") {
+            ALOGI("Initialize with VR_MODE on");
+            mHintManager->DoHint("VR_MODE");
+            mVRModeOn = true;
+        } else if (state == "VR_SUSTAINED_PERFORMANCE") {
+            ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR_MODE on");
+            mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+            mSustainedPerfModeOn = true;
+            mVRModeOn = true;
+        } else {
+            ALOGI("Initialize PowerHAL");
+        }
+
+        state = android::base::GetProperty(kPowerHalAudioProp, "");
+        if (state == "AUDIO_LOW_LATENCY") {
+            ALOGI("Initialize with AUDIO_LOW_LATENCY on");
+            mHintManager->DoHint("AUDIO_LOW_LATENCY");
+        }
+
+        state = android::base::GetProperty(kPowerHalRenderingProp, "");
+        if (state == "EXPENSIVE_RENDERING") {
+            ALOGI("Initialize with EXPENSIVE_RENDERING on");
+            mHintManager->DoHint("EXPENSIVE_RENDERING");
+        }
+        // Now start to take powerhint
+        mReady.store(true);
+        ALOGI("PowerHAL ready to process hints");
+    });
+    mInitThread.detach();
+}
+
+// Methods from ::android::hardware::power::V1_0::IPower follow.
+Return<void> Power::setInteractive(bool /* interactive */) {
+    return Void();
+}
+
+Return<void> Power::powerHint(PowerHint_1_0 hint, int32_t data) {
+    if (!mReady) {
+        return Void();
+    }
+    ATRACE_INT(android::hardware::power::V1_0::toString(hint).c_str(), data);
+    ALOGD_IF(hint != PowerHint_1_0::INTERACTION, "%s: %d",
+             android::hardware::power::V1_0::toString(hint).c_str(), static_cast<int>(data));
+    switch (hint) {
+        case PowerHint_1_0::INTERACTION:
+            if (mVRModeOn || mSustainedPerfModeOn) {
+                ALOGV("%s: ignoring due to other active perf hints", __func__);
+            } else {
+                mInteractionHandler->Acquire(data);
+            }
+            break;
+        case PowerHint_1_0::SUSTAINED_PERFORMANCE:
+            if (data && !mSustainedPerfModeOn) {
+                if (!mVRModeOn) {  // Sustained mode only.
+                    mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+                } else {  // Sustained + VR mode.
+                    mHintManager->EndHint("VR_MODE");
+                    mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+                }
+                mSustainedPerfModeOn = true;
+            } else if (!data && mSustainedPerfModeOn) {
+                mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
+                mHintManager->EndHint("SUSTAINED_PERFORMANCE");
+                if (mVRModeOn) {  // Switch back to VR Mode.
+                    mHintManager->DoHint("VR_MODE");
+                }
+                mSustainedPerfModeOn = false;
+            }
+            break;
+        case PowerHint_1_0::VR_MODE:
+            if (data && !mVRModeOn) {
+                if (!mSustainedPerfModeOn) {  // VR mode only.
+                    mHintManager->DoHint("VR_MODE");
+                } else {  // Sustained + VR mode.
+                    mHintManager->EndHint("SUSTAINED_PERFORMANCE");
+                    mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
+                }
+                mVRModeOn = true;
+            } else if (!data && mVRModeOn) {
+                mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
+                mHintManager->EndHint("VR_MODE");
+                if (mSustainedPerfModeOn) {  // Switch back to sustained Mode.
+                    mHintManager->DoHint("SUSTAINED_PERFORMANCE");
+                }
+                mVRModeOn = false;
+            }
+            break;
+        case PowerHint_1_0::LAUNCH:
+            if (mVRModeOn || mSustainedPerfModeOn) {
+                ALOGV("%s: ignoring due to other active perf hints", __func__);
+            } else {
+                if (data) {
+                    // Hint until canceled
+                    mHintManager->DoHint("LAUNCH");
+                } else {
+                    mHintManager->EndHint("LAUNCH");
+                }
+            }
+            break;
+        case PowerHint_1_0::LOW_POWER:
+            if (data) {
+                // Device in battery saver mode, enable display low power mode
+                set_display_lpm(true);
+            } else {
+                // Device exiting battery saver mode, disable display low power mode
+                set_display_lpm(false);
+            }
+            break;
+        default:
+            break;
+    }
+    return Void();
+}
+
+Return<void> Power::setFeature(Feature /*feature*/, bool /*activate*/) {
+    // Nothing to do
+    return Void();
+}
+
+Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
+    LOG(ERROR) << "getPlatformLowPowerStats not supported. Use IPowerStats HAL.";
+    _hidl_cb({}, Status::SUCCESS);
+    return Void();
+}
+
+// Methods from ::android::hardware::power::V1_1::IPower follow.
+Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
+    LOG(ERROR) << "getSubsystemLowPowerStats not supported. Use IPowerStats HAL.";
+    _hidl_cb({}, Status::SUCCESS);
+    return Void();
+}
+
+Return<void> Power::powerHintAsync(PowerHint_1_0 hint, int32_t data) {
+    // just call the normal power hint in this oneway function
+    return powerHint(hint, data);
+}
+
+// Methods from ::android::hardware::power::V1_2::IPower follow.
+Return<void> Power::powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) {
+    if (!mReady) {
+        return Void();
+    }
+
+    ATRACE_INT(android::hardware::power::V1_2::toString(hint).c_str(), data);
+    ALOGD_IF(hint >= PowerHint_1_2::AUDIO_STREAMING, "%s: %d",
+             android::hardware::power::V1_2::toString(hint).c_str(), static_cast<int>(data));
+
+    switch (hint) {
+        case PowerHint_1_2::AUDIO_LOW_LATENCY:
+            if (data) {
+                // Hint until canceled
+                mHintManager->DoHint("AUDIO_LOW_LATENCY");
+            } else {
+                mHintManager->EndHint("AUDIO_LOW_LATENCY");
+            }
+            break;
+        case PowerHint_1_2::AUDIO_STREAMING:
+            if (mVRModeOn || mSustainedPerfModeOn) {
+                ALOGV("%s: ignoring due to other active perf hints", __func__);
+            } else {
+                if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::AUDIO_STREAMING_ON)) {
+                    mHintManager->DoHint("AUDIO_STREAMING");
+                } else if (data ==
+                           static_cast<int32_t>(AUDIO_STREAMING_HINT::AUDIO_STREAMING_OFF)) {
+                    mHintManager->EndHint("AUDIO_STREAMING");
+                } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_SHORT)) {
+                    mHintManager->DoHint("TPU_BOOST",
+                                         std::chrono::milliseconds(TPU_HINT_DURATION_MS::SHORT));
+                } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_LONG)) {
+                    mHintManager->DoHint("TPU_BOOST",
+                                         std::chrono::milliseconds(TPU_HINT_DURATION_MS::LONG));
+                } else if (data == static_cast<int32_t>(AUDIO_STREAMING_HINT::TPU_BOOST_OFF)) {
+                    mHintManager->EndHint("TPU_BOOST");
+                } else {
+                    ALOGE("AUDIO STREAMING INVALID DATA: %d", data);
+                }
+            }
+            break;
+        case PowerHint_1_2::CAMERA_LAUNCH:
+            if (data > 0) {
+                mHintManager->DoHint("CAMERA_LAUNCH");
+            } else if (data == 0) {
+                mHintManager->EndHint("CAMERA_LAUNCH");
+            } else {
+                ALOGE("CAMERA LAUNCH INVALID DATA: %d", data);
+            }
+            break;
+        case PowerHint_1_2::CAMERA_STREAMING: {
+            const enum CameraStreamingMode mode = static_cast<enum CameraStreamingMode>(data);
+            if (mode < CAMERA_STREAMING_OFF || mode >= CAMERA_STREAMING_MAX) {
+                ALOGE("CAMERA STREAMING INVALID Mode: %d", mode);
+                break;
+            }
+
+            if (mCameraStreamingMode == mode)
+                break;
+
+            // turn it off first if any previous hint.
+            if ((mCameraStreamingMode != CAMERA_STREAMING_OFF)) {
+                const auto modeValue = kCamStreamingHint.at(mCameraStreamingMode);
+                mHintManager->EndHint(modeValue);
+                if ((mCameraStreamingMode != CAMERA_STREAMING_SECURE)) {
+                    // Boost 1s for tear down if not secure streaming use case
+                    mHintManager->DoHint("CAMERA_LAUNCH", std::chrono::seconds(1));
+                }
+            }
+
+            if (mode != CAMERA_STREAMING_OFF) {
+                const auto hintValue = kCamStreamingHint.at(mode);
+                mHintManager->DoHint(hintValue);
+            }
+
+            mCameraStreamingMode = mode;
+            const auto prop = (mCameraStreamingMode == CAMERA_STREAMING_OFF)
+                                  ? ""
+                                  : kCamStreamingHint.at(mode).c_str();
+            if (!android::base::SetProperty(kPowerHalStateProp, prop)) {
+                ALOGE("%s: could set powerHAL state %s property", __func__, prop);
+            }
+            break;
+        }
+        case PowerHint_1_2::CAMERA_SHOT:
+            if (data > 0) {
+                mHintManager->DoHint("CAMERA_SHOT", std::chrono::milliseconds(data));
+            } else if (data == 0) {
+                mHintManager->EndHint("CAMERA_SHOT");
+            } else {
+                ALOGE("CAMERA SHOT INVALID DATA: %d", data);
+            }
+            break;
+        default:
+            return powerHint(static_cast<PowerHint_1_0>(hint), data);
+    }
+    return Void();
+}
+
+// Methods from ::android::hardware::power::V1_3::IPower follow.
+Return<void> Power::powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) {
+    if (!mReady) {
+        return Void();
+    }
+
+    if (hint == PowerHint_1_3::EXPENSIVE_RENDERING) {
+        ATRACE_INT(android::hardware::power::V1_3::toString(hint).c_str(), data);
+        if (mVRModeOn || mSustainedPerfModeOn) {
+            ALOGV("%s: ignoring due to other active perf hints", __func__);
+        } else {
+            if (data > 0) {
+                mHintManager->DoHint("EXPENSIVE_RENDERING");
+            } else {
+                mHintManager->EndHint("EXPENSIVE_RENDERING");
+            }
+        }
+    } else {
+        return powerHintAsync_1_2(static_cast<PowerHint_1_2>(hint), data);
+    }
+    return Void();
+}
+
+constexpr const char *boolToString(bool b) {
+    return b ? "true" : "false";
+}
+
+Return<void> Power::debug(const hidl_handle &handle, const hidl_vec<hidl_string> &) {
+    if (handle != nullptr && handle->numFds >= 1 && mReady) {
+        int fd = handle->data[0];
+
+        std::string buf(android::base::StringPrintf(
+            "HintManager Running: %s\n"
+            "VRMode: %s\n"
+            "CameraStreamingMode: %s\n"
+            "SustainedPerformanceMode: %s\n",
+            boolToString(mHintManager->IsRunning()), boolToString(mVRModeOn),
+            kCamStreamingHint.at(mCameraStreamingMode).c_str(),
+            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 Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
diff --git a/hidl/power-libperfmgr/Power.h b/hidl/power-libperfmgr/Power.h
new file mode 100644 (file)
index 0000000..b43fecd
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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_POWER_H_
+#define POWER_LIBPERFMGR_POWER_H_
+
+#include <atomic>
+#include <memory>
+#include <thread>
+
+#include <android/hardware/power/1.3/IPower.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <perfmgr/HintManager.h>
+
+#include "CameraMode.h"
+#include "InteractionHandler.h"
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_3 {
+namespace implementation {
+
+using ::InteractionHandler;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_3::IPower;
+using PowerHint_1_0 = ::android::hardware::power::V1_0::PowerHint;
+using PowerHint_1_2 = ::android::hardware::power::V1_2::PowerHint;
+using PowerHint_1_3 = ::android::hardware::power::V1_3::PowerHint;
+using ::android::perfmgr::HintManager;
+
+class Power : public IPower {
+  public:
+    // Methods from ::android::hardware::power::V1_0::IPower follow.
+
+    Power();
+
+    Return<void> setInteractive(bool /* interactive */) override;
+    Return<void> powerHint(PowerHint_1_0 hint, int32_t data) override;
+    Return<void> setFeature(Feature feature, bool activate) override;
+    Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override;
+
+    // Methods from ::android::hardware::power::V1_1::IPower follow.
+    Return<void> getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) override;
+    Return<void> powerHintAsync(PowerHint_1_0 hint, int32_t data) override;
+
+    // Methods from ::android::hardware::power::V1_2::IPower follow.
+    Return<void> powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) override;
+
+    // Methods from ::android::hardware::power::V1_3::IPower follow.
+    Return<void> powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle &fd, const hidl_vec<hidl_string> &args) override;
+
+  private:
+    std::shared_ptr<HintManager> mHintManager;
+    std::unique_ptr<InteractionHandler> mInteractionHandler;
+    std::atomic<bool> mVRModeOn;
+    std::atomic<bool> mSustainedPerfModeOn;
+    std::atomic<enum CameraStreamingMode> mCameraStreamingMode;
+    std::atomic<bool> mReady;
+    std::thread mInitThread;
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
+
+#endif  // POWER_LIBPERFMGR_POWER_H_
diff --git a/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel-libperfmgr.rc b/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel-libperfmgr.rc
new file mode 100644 (file)
index 0000000..6179f6e
--- /dev/null
@@ -0,0 +1,26 @@
+service vendor.power-hal-1-3 /vendor/bin/hw/android.hardware.power@1.3-service.pixel-libperfmgr
+    class hal
+    user root
+    group system
+    priority -20
+    interface android.hardware.power@1.0::IPower default
+    interface android.hardware.power@1.1::IPower default
+    interface android.hardware.power@1.2::IPower default
+    interface android.hardware.power@1.3::IPower default
+
+# 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-1-3
+
+# restart powerHAL when cameraHAL died
+on property:init.svc.vendor.camera-provider-2-4=restarting && property:vendor.powerhal.state=CAMERA_STREAMING
+   setprop vendor.powerhal.state ""
+   restart vendor.power-hal-1-3
+
+# restart powerHAL when audioHAL died
+on property:init.svc.vendor.audio-hal-2-0=restarting && property:vendor.powerhal.audio=AUDIO_LOW_LATENCY
+   setprop vendor.powerhal.audio ""
+   restart vendor.power-hal-1-3
diff --git a/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel.xml b/hidl/power-libperfmgr/android.hardware.power@1.3-service.pixel.xml
new file mode 100644 (file)
index 0000000..e52398c
--- /dev/null
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+     <hal format="hidl">
+        <name>android.hardware.power</name>
+        <transport>hwbinder</transport>
+        <version>1.3</version>
+        <interface>
+            <name>IPower</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/hidl/power-libperfmgr/display-helper.cpp b/hidl/power-libperfmgr/display-helper.cpp
new file mode 100644 (file)
index 0000000..2369c63
--- /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.
+ */
+
+#define LOG_NIDEBUG 0
+#define LOG_TAG "android.hardware.power@1.3-service.pixel-libperfmgr"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/log.h>
+
+#include "display-helper.h"
+
+#define DAEMON_SOCKET "pps"
+
+static int daemon_socket = -1;
+
+static int connectPPDaemon() {
+    // Setup socket connection, if not already done.
+    if (daemon_socket < 0)
+        daemon_socket =
+                socket_local_client(DAEMON_SOCKET, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+
+    if (daemon_socket < 0) {
+        ALOGE("Connecting to socket failed: %s", strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int ppdComm(const char *cmd) {
+    int ret = -1;
+
+    ret = connectPPDaemon();
+    if (ret < 0)
+        return ret;
+
+    ret = write(daemon_socket, cmd, strlen(cmd));
+    if (ret < 0) {
+        ALOGE("Failed to send data over socket, %s", strerror(errno));
+        return ret;
+    }
+    return 0;
+}
+
+void set_display_lpm(int enable) {
+    ALOGI("set_display_lpm state: %d", enable);
+    if (enable) {
+        ppdComm("foss:on");
+    } else {
+        ppdComm("foss:off");
+    }
+}
diff --git a/hidl/power-libperfmgr/display-helper.h b/hidl/power-libperfmgr/display-helper.h
new file mode 100644 (file)
index 0000000..70b9697
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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_DISPLAY_HELPER_H_
+#define POWER_LIBPERFMGR_DISPLAY_HELPER_H_
+
+enum display_lpm_state {
+    DISPLAY_LPM_OFF = 0,
+    DISPLAY_LPM_ON,
+    DISPLAY_LPM_UNKNOWN,
+};
+
+void set_display_lpm(int enable);
+
+#endif  // POWER_LIBPERFMGR_DISPLAY_HELPER_H_
diff --git a/hidl/power-libperfmgr/service.cpp b/hidl/power-libperfmgr/service.cpp
new file mode 100644 (file)
index 0000000..7bcc907
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.power@1.3-service.pixel-libperfmgr"
+
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Power.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::V1_3::IPower;
+using android::hardware::power::V1_3::implementation::Power;
+
+int main(int /* argc */, char ** /* argv */) {
+    ALOGI("Power HAL Service 1.3 for Pixel is starting.");
+
+    android::sp<IPower> service = new Power();
+    if (service == nullptr) {
+        ALOGE("Can not create an instance of Power HAL Iface, exiting.");
+        return 1;
+    }
+    android::hardware::setMinSchedulerPolicy(service, SCHED_NORMAL, -20);
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    status_t status = service->registerAsService();
+    if (status != OK) {
+        ALOGE("Could not register service for Power HAL Iface (%d), exiting.", status);
+        return 1;
+    }
+
+    ALOGI("Power Service is ready");
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("Power Service is shutting down");
+    return 1;
+}