power: Handle launch and interaction hints

Co-authored-by: dianlujitao <dianlujitao@lineageos.org>
Co-authored-by: Michael Bestas <mkbestas@lineageos.org>
Co-authored-by: Quallenauge <Hamsi2k@freenet.de>
Co-authored-by: tomascus <arbiter1000@gmail.com>
Co-authored-by: Wei Wang <wvw@google.com>
Change-Id: I472a177e0a13b0c4201cf0b1e5ddee18a785b683
diff --git a/Android.mk b/Android.mk
index 739b75c..4724c65 100644
--- a/Android.mk
+++ b/Android.mk
@@ -59,10 +59,6 @@
 LOCAL_SRC_FILES += power-845.c
 endif
 
-ifeq ($(call is-board-platform-in-list,msmnile), true)
-LOCAL_SRC_FILES += power-msmnile.c
-endif
-
 endif # End of board specific list
 
 ifneq ($(TARGET_POWERHAL_MODE_EXT),)
diff --git a/Power.cpp b/Power.cpp
index cb16c92..1c677bc 100644
--- a/Power.cpp
+++ b/Power.cpp
@@ -84,7 +84,6 @@
         case Mode::DOUBLE_TAP_TO_WAKE:
 #endif
         case Mode::LOW_POWER:
-        case Mode::LAUNCH:
         case Mode::DEVICE_IDLE:
         case Mode::DISPLAY_INACTIVE:
         case Mode::AUDIO_STREAMING_LOW_LATENCY:
@@ -98,9 +97,11 @@
         case Mode::EXPENSIVE_RENDERING:
             set_expensive_rendering(enabled);
             break;
+        case Mode::LAUNCH:
+            power_hint(POWER_HINT_LAUNCH, enabled ? &enabled : NULL);
+            break;
         case Mode::INTERACTIVE:
             setInteractive(enabled);
-            power_hint(POWER_HINT_INTERACTION, NULL);
             break;
         case Mode::SUSTAINED_PERFORMANCE:
         case Mode::FIXED_PERFORMANCE:
@@ -131,6 +132,7 @@
 #ifdef TAP_TO_WAKE_NODE
         case Mode::DOUBLE_TAP_TO_WAKE:
 #endif
+        case Mode::LAUNCH:
         case Mode::INTERACTIVE:
         case Mode::SUSTAINED_PERFORMANCE:
         case Mode::FIXED_PERFORMANCE:
@@ -146,14 +148,30 @@
 ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
     LOG(VERBOSE) << "Power setBoost: " << static_cast<int32_t>(type)
                  << ", duration: " << durationMs;
+    switch (type) {
+        case Boost::INTERACTION:
+            power_hint(POWER_HINT_INTERACTION, &durationMs);
+            break;
+        default:
+            LOG(INFO) << "Boost " << static_cast<int32_t>(type) << "Not Supported";
+            break;
+    }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool* _aidl_return) {
     LOG(INFO) << "Power isBoostSupported: " << static_cast<int32_t>(type);
-    *_aidl_return = false;
+    switch (type) {
+        case Boost::INTERACTION:
+            *_aidl_return = true;
+            break;
+        default:
+            *_aidl_return = false;
+            break;
+    }
     return ndk::ScopedAStatus::ok();
 }
+
 ndk::ScopedAStatus Power::createHintSession(int32_t tgid, int32_t uid,
                                             const std::vector<int32_t>& threadIds,
                                             int64_t durationNanos,
diff --git a/performance.h b/performance.h
index 7b40331..1a8fad6 100644
--- a/performance.h
+++ b/performance.h
@@ -42,6 +42,22 @@
 #define VENDOR_HINT_DISPLAY_OFF 0x00001040
 #define VENDOR_HINT_DISPLAY_ON 0x00001041
 
+#define VENDOR_HINT_SCROLL_BOOST 0x00001080
+#define VENDOR_HINT_FIRST_LAUNCH_BOOST 0x00001081
+
+enum SCROLL_BOOST_TYPE {
+    SCROLL_VERTICAL = 1,
+    SCROLL_HORIZONTAL = 2,
+    SCROLL_PANEL_VIEW = 3,
+    SCROLL_PREFILING = 4,
+};
+
+enum LAUNCH_BOOST_TYPE {
+    LAUNCH_BOOST_V1 = 1,
+    LAUNCH_BOOST_V2 = 2,
+    LAUNCH_BOOST_V3 = 3,
+};
+
 enum SCREEN_DISPLAY_TYPE {
     DISPLAY_OFF = 0x00FF,
 };
diff --git a/power-845.c b/power-845.c
index 0044bf6..becee95 100644
--- a/power-845.c
+++ b/power-845.c
@@ -49,7 +49,6 @@
 #include "power-common.h"
 #include "utils.h"
 
-#define CHECK_HANDLE(x) ((x) > 0)
 #define NUM_PERF_MODES 3
 
 typedef enum {
@@ -189,12 +188,6 @@
         case POWER_HINT_VR_MODE:
             ret_val = process_perf_hint(data, VR_MODE);
             break;
-        case POWER_HINT_INTERACTION: {
-            int resources[] = {MIN_FREQ_LITTLE_CORE_0, 0x514};
-            int duration = 100;
-            interaction(duration, ARRAY_SIZE(resources), resources);
-            ret_val = HINT_HANDLED;
-        } break;
         default:
             break;
     }
diff --git a/power-8996.c b/power-8996.c
index 8202942..48d9048 100644
--- a/power-8996.c
+++ b/power-8996.c
@@ -47,7 +47,6 @@
 #include "power-common.h"
 #include "utils.h"
 
-#define CHECK_HANDLE(x) ((x) > 0)
 #define NUM_PERF_MODES 3
 
 static int video_encode_hint_sent;
diff --git a/power-8998.c b/power-8998.c
index 0b03aef..3e4b7b9 100644
--- a/power-8998.c
+++ b/power-8998.c
@@ -48,7 +48,6 @@
 #include "power-common.h"
 #include "utils.h"
 
-#define CHECK_HANDLE(x) ((x) > 0)
 #define NUM_PERF_MODES 3
 
 typedef enum {
@@ -188,11 +187,6 @@
         case POWER_HINT_VR_MODE:
             ret_val = process_perf_hint(data, VR_MODE);
             break;
-        case POWER_HINT_INTERACTION:
-            if (current_mode != NORMAL_MODE) {
-                ret_val = HINT_HANDLED;
-            }
-            break;
         default:
             break;
     }
diff --git a/power-common.c b/power-common.c
index 9665068..16bf084 100644
--- a/power-common.c
+++ b/power-common.c
@@ -51,6 +51,10 @@
 static struct hint_handles handles[NUM_HINTS];
 static int handleER = 0;
 
+const int kMaxLaunchDuration = 5000;      /* ms */
+const int kMaxInteractiveDuration = 5000; /* ms */
+const int kMinInteractiveDuration = 500;  /* ms */
+
 void power_init() {
     ALOGI("Initing");
 
@@ -60,6 +64,69 @@
     }
 }
 
+void process_interaction_hint(void* data) {
+    static struct timespec s_previous_boost_timespec;
+    static int s_previous_duration = 0;
+    static int prev_interaction_handle = -1;
+
+    struct timespec cur_boost_timespec;
+    long long elapsed_time;
+    int duration = kMinInteractiveDuration;
+
+    if (data) {
+        int input_duration = *((int*)data);
+        if (input_duration > duration) {
+            duration = (input_duration > kMaxInteractiveDuration) ? kMaxInteractiveDuration
+                                                                  : input_duration;
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
+    // don't hint if it's been less than 250ms since last boost
+    // also detect if we're doing anything resembling a fling
+    // support additional boosting in case of flings
+    if (elapsed_time < 250000 && duration <= 750) {
+        return;
+    }
+    s_previous_boost_timespec = cur_boost_timespec;
+    s_previous_duration = duration;
+
+    int interaction_handle =
+            perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
+
+    if (CHECK_HANDLE(prev_interaction_handle)) {
+        release_request(prev_interaction_handle);
+    }
+    prev_interaction_handle = interaction_handle;
+}
+
+void process_activity_launch_hint(void* data) {
+    static int launch_handle = -1;
+    static int launch_mode = 0;
+
+    // release lock early if launch has finished
+    if (!data) {
+        if (CHECK_HANDLE(launch_handle)) {
+            release_request(launch_handle);
+            launch_handle = -1;
+        }
+        launch_mode = 0;
+        return;
+    }
+
+    if (!launch_mode) {
+        launch_handle = perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST,
+                                                   kMaxLaunchDuration, LAUNCH_BOOST_V1);
+        if (!CHECK_HANDLE(launch_handle)) {
+            ALOGE("Failed to perform launch boost");
+            return;
+        }
+        launch_mode = 1;
+    }
+}
+
 int __attribute__((weak)) power_hint_override(power_hint_t hint, void* data) {
     return HINT_NONE;
 }
@@ -74,12 +141,6 @@
         case POWER_HINT_VR_MODE:
             ALOGI("VR mode power hint not handled in power_hint_override");
             break;
-        case POWER_HINT_INTERACTION: {
-            int resources[] = {0x702, 0x20F, 0x30F};
-            int duration = 3000;
-
-            interaction(duration, sizeof(resources) / sizeof(resources[0]), resources);
-        } break;
         // fall through below, hints will fail if not defined in powerhint.xml
         case POWER_HINT_SUSTAINED_PERFORMANCE:
         case POWER_HINT_VIDEO_ENCODE:
@@ -99,6 +160,12 @@
                 }
             }
             break;
+        case POWER_HINT_INTERACTION:
+            process_interaction_hint(data);
+            break;
+        case POWER_HINT_LAUNCH:
+            process_activity_launch_hint(data);
+            break;
         default:
             break;
     }
diff --git a/power-common.h b/power-common.h
index 16ba0db..02fd557 100644
--- a/power-common.h
+++ b/power-common.h
@@ -52,6 +52,7 @@
 void set_interactive(int on);
 
 #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
+#define CHECK_HANDLE(x) ((x) > 0)
 
 #ifdef __cplusplus
 }
diff --git a/power-msmnile.c b/power-msmnile.c
deleted file mode 100644
index d92a5ff..0000000
--- a/power-msmnile.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * *    * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- *       copyright notice, this list of conditions and the following
- *       disclaimer in the documentation and/or other materials provided
- *       with the distribution.
- *     * Neither the name of The Linux Foundation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define LOG_NIDEBUG 0
-
-#include <dlfcn.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#define LOG_TAG "QTI PowerHAL"
-#include <hardware/hardware.h>
-#include <hardware/power.h>
-#include <log/log.h>
-
-#include "performance.h"
-#include "power-common.h"
-#include "utils.h"
-
-int power_hint_override(power_hint_t hint, void* data) {
-    int ret_val = HINT_NONE;
-    switch (hint) {
-        case POWER_HINT_INTERACTION: {
-            int resources[] = {MIN_FREQ_LITTLE_CORE_0, 0x514};
-            int duration = 100;
-            interaction(duration, ARRAY_SIZE(resources), resources);
-            ret_val = HINT_HANDLED;
-        }
-        default:
-            break;
-    }
-    return ret_val;
-}
diff --git a/utils.c b/utils.c
index 06c1efd..f6b4a5e 100644
--- a/utils.c
+++ b/utils.c
@@ -43,6 +43,9 @@
 #define LOG_TAG "QTI PowerHAL"
 #include <log/log.h>
 
+#define USINSEC 1000000L
+#define NSINUS 1000L
+
 #define SOC_ID_0 "/sys/devices/soc0/soc_id"
 #define SOC_ID_1 "/sys/devices/system/soc/soc0/id"
 
@@ -258,6 +261,20 @@
     return lock_handle;
 }
 
+// Same as perf_hint_enable, but with the ability to
+// choose the type
+int perf_hint_enable_with_type(int hint_id, int duration, int type) {
+    int lock_handle = 0;
+
+    if (qcopt_handle) {
+        if (perf_hint) {
+            lock_handle = perf_hint(hint_id, NULL, duration, type);
+            if (lock_handle == -1) ALOGE("Failed to acquire lock.");
+        }
+    }
+    return lock_handle;
+}
+
 void release_request(int lock_handle) {
     if (qcopt_handle && perf_lock_rel) perf_lock_rel(lock_handle);
 }
@@ -364,3 +381,10 @@
     close(fd);
     return soc_id;
 }
+
+long long calc_timespan_us(struct timespec start, struct timespec end) {
+    long long diff_in_us = 0;
+    diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
+    diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
+    return diff_in_us;
+}
diff --git a/utils.h b/utils.h
index abc7c79..2feb4c3 100644
--- a/utils.h
+++ b/utils.h
@@ -47,7 +47,9 @@
 void interaction(int duration, int num_args, int opt_list[]);
 int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[]);
 int perf_hint_enable(int hint_id, int duration);
+int perf_hint_enable_with_type(int hint_id, int duration, int type);
 
+long long calc_timespan_us(struct timespec start, struct timespec end);
 int get_soc_id(void);
 
 PropVal perf_get_property(const char* prop, const char* def_val);